diff options
528 files changed, 13268 insertions, 12997 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java deleted file mode 100644 index 8bf13eec6249..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearch.java +++ /dev/null @@ -1,854 +0,0 @@ -/* - * 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 android.app.appsearch; - -import android.annotation.CurrentTimeMillisLong; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.appsearch.AppSearchSchema.PropertyConfig; -import android.os.Bundle; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Objects; - -/** - * Collection of all AppSearch Document Types. - * - * @hide - */ -// TODO(b/143789408) Spilt this class to make all subclasses to their own file. -public final class AppSearch { - - private AppSearch() {} - /** - * Represents a document unit. - * - * <p>Documents are constructed via {@link Document.Builder}. - * - * @hide - */ - // TODO(b/143789408) set TTL for document in mProtoBuilder - // TODO(b/144518768) add visibility field if the stakeholders are comfortable with a no-op - // opt-in for this release. - public static class Document { - private static final String TAG = "AppSearch.Document"; - - /** - * The maximum number of elements in a repeatable field. Will reject the request if exceed - * this limit. - */ - private static final int MAX_REPEATED_PROPERTY_LENGTH = 100; - - /** - * The maximum {@link String#length} of a {@link String} field. Will reject the request if - * {@link String}s longer than this. - */ - private static final int MAX_STRING_LENGTH = 20_000; - - /** - * Contains {@link Document} basic information (uri, schemaType etc) and properties ordered - * by keys. - */ - @NonNull - private final DocumentProto mProto; - - /** Contains all properties in {@link #mProto} to support get properties via keys. */ - @NonNull - private final Bundle mPropertyBundle; - - /** - * Create a new {@link Document}. - * @param proto Contains {@link Document} basic information (uri, schemaType etc) and - * properties ordered by keys. - * @param propertyBundle Contains all properties in {@link #mProto} to support get - * properties via keys. - */ - private Document(@NonNull DocumentProto proto, @NonNull Bundle propertyBundle) { - this.mProto = proto; - this.mPropertyBundle = propertyBundle; - } - - /** - * Create a new {@link Document} from an existing instance. - * - * <p>This method should be only used by constructor of a subclass. - */ - // TODO(b/143789408) add constructor take DocumentProto to create a document. - protected Document(@NonNull Document document) { - this(document.mProto, document.mPropertyBundle); - } - - /** @hide */ - Document(@NonNull DocumentProto documentProto) { - this(documentProto, new Bundle()); - for (int i = 0; i < documentProto.getPropertiesCount(); i++) { - PropertyProto property = documentProto.getProperties(i); - String name = property.getName(); - if (property.getStringValuesCount() > 0) { - String[] values = new String[property.getStringValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getStringValues(j); - } - mPropertyBundle.putStringArray(name, values); - } else if (property.getInt64ValuesCount() > 0) { - long[] values = new long[property.getInt64ValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getInt64Values(j); - } - mPropertyBundle.putLongArray(property.getName(), values); - } else if (property.getDoubleValuesCount() > 0) { - double[] values = new double[property.getDoubleValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getDoubleValues(j); - } - mPropertyBundle.putDoubleArray(property.getName(), values); - } else if (property.getBooleanValuesCount() > 0) { - boolean[] values = new boolean[property.getBooleanValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getBooleanValues(j); - } - mPropertyBundle.putBooleanArray(property.getName(), values); - } else if (property.getBytesValuesCount() > 0) { - byte[][] values = new byte[property.getBytesValuesCount()][]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getBytesValues(j).toByteArray(); - } - mPropertyBundle.putObject(name, values); - } else if (property.getDocumentValuesCount() > 0) { - Document[] values = new Document[property.getDocumentValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = new Document(property.getDocumentValues(j)); - } - mPropertyBundle.putObject(name, values); - } else { - throw new IllegalStateException("Unknown type of value: " + name); - } - } - } - - /** - * Creates a new {@link Document.Builder}. - * - * @param uri The uri of {@link Document}. - * @param schemaType The schema type of the {@link Document}. The passed-in - * {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior to - * inserting a document of this {@code schemaType} into the AppSearch index using - * {@link AppSearchManager#put}. Otherwise, the document will be rejected by - * {@link AppSearchManager#put}. - * @hide - */ - @NonNull - public static Builder newBuilder(@NonNull String uri, @NonNull String schemaType) { - return new Builder(uri, schemaType); - } - - /** - * Get the {@link DocumentProto} of the {@link Document}. - * - * <p>The {@link DocumentProto} contains {@link Document}'s basic information and all - * properties ordered by keys. - * @hide - */ - @NonNull - @VisibleForTesting - public DocumentProto getProto() { - return mProto; - } - - /** - * Get the uri of the {@link Document}. - * - * @hide - */ - @NonNull - public String getUri() { - return mProto.getUri(); - } - - /** - * Get the schema type of the {@link Document}. - * @hide - */ - @NonNull - public String getSchemaType() { - return mProto.getSchema(); - } - - /** - * Get the creation timestamp in milliseconds of the {@link Document}. Value will be in the - * {@link System#currentTimeMillis()} time base. - * - * @hide - */ - @CurrentTimeMillisLong - public long getCreationTimestampMillis() { - return mProto.getCreationTimestampMs(); - } - - /** - * Returns the score of the {@link Document}. - * - * <p>The score is a query-independent measure of the document's quality, relative to other - * {@link Document}s of the same type. - * - * <p>The default value is 0. - * - * @hide - */ - public int getScore() { - return mProto.getScore(); - } - - /** - * Retrieve a {@link String} value by key. - * - * @param key The key to look for. - * @return The first {@link String} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public String getPropertyString(@NonNull String key) { - String[] propertyArray = getPropertyStringArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("String", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Long} value by key. - * - * @param key The key to look for. - * @return The first {@link Long} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Long getPropertyLong(@NonNull String key) { - long[] propertyArray = getPropertyLongArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("Long", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Double} value by key. - * - * @param key The key to look for. - * @return The first {@link Double} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Double getPropertyDouble(@NonNull String key) { - double[] propertyArray = getPropertyDoubleArray(key); - // TODO(tytytyww): Add support double array to ArraysUtils.isEmpty(). - if (propertyArray == null || propertyArray.length == 0) { - return null; - } - warnIfSinglePropertyTooLong("Double", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Boolean} value by key. - * - * @param key The key to look for. - * @return The first {@link Boolean} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Boolean getPropertyBoolean(@NonNull String key) { - boolean[] propertyArray = getPropertyBooleanArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length); - return propertyArray[0]; - } - - /** Prints a warning to logcat if the given propertyLength is greater than 1. */ - private static void warnIfSinglePropertyTooLong( - @NonNull String propertyType, @NonNull String key, int propertyLength) { - if (propertyLength > 1) { - Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength - + " elements. Only the first one will be returned from " - + "getProperty" + propertyType + "(). Try getProperty" + propertyType - + "Array()."); - } - } - - /** - * Retrieve a repeated {@code String} property by key. - * - * @param key The key to look for. - * @return The {@code String[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public String[] getPropertyStringArray(@NonNull String key) { - return getAndCastPropertyArray(key, String[].class); - } - - /** - * Retrieve a repeated {@code long} property by key. - * - * @param key The key to look for. - * @return The {@code long[]} associated with the given key, or {@code null} if no value is - * set or the value is of a different type. - * @hide - */ - @Nullable - public long[] getPropertyLongArray(@NonNull String key) { - return getAndCastPropertyArray(key, long[].class); - } - - /** - * Retrieve a repeated {@code double} property by key. - * - * @param key The key to look for. - * @return The {@code double[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public double[] getPropertyDoubleArray(@NonNull String key) { - return getAndCastPropertyArray(key, double[].class); - } - - /** - * Retrieve a repeated {@code boolean} property by key. - * - * @param key The key to look for. - * @return The {@code boolean[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public boolean[] getPropertyBooleanArray(@NonNull String key) { - return getAndCastPropertyArray(key, boolean[].class); - } - - /** - * Gets a repeated property of the given key, and casts it to the given class type, which - * must be an array class type. - */ - @Nullable - private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) { - Object value = mPropertyBundle.get(key); - if (value == null) { - return null; - } - try { - return tClass.cast(value); - } catch (ClassCastException e) { - Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e); - return null; - } - } - - @Override - public boolean equals(@Nullable Object other) { - // Check only proto's equality is sufficient here since all properties in - // mPropertyBundle are ordered by keys and stored in proto. - if (this == other) { - return true; - } - if (!(other instanceof Document)) { - return false; - } - Document otherDocument = (Document) other; - return this.mProto.equals(otherDocument.mProto); - } - - @Override - public int hashCode() { - // Hash only proto is sufficient here since all properties in mPropertyBundle are - // ordered by keys and stored in proto. - return mProto.hashCode(); - } - - @Override - public String toString() { - return mProto.toString(); - } - - /** - * The builder class for {@link Document}. - * - * @param <BuilderType> Type of subclass who extend this. - * @hide - */ - public static class Builder<BuilderType extends Builder> { - - private final Bundle mPropertyBundle = new Bundle(); - private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder(); - private final BuilderType mBuilderTypeInstance; - - /** - * Create a new {@link Document.Builder}. - * - * @param uri The uri of {@link Document}. - * @param schemaType The schema type of the {@link Document}. The passed-in - * {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior - * to inserting a document of this {@code schemaType} into the AppSearch index using - * {@link AppSearchManager#put}. Otherwise, the document will be rejected by - * {@link AppSearchManager#put}. - * @hide - */ - protected Builder(@NonNull String uri, @NonNull String schemaType) { - mBuilderTypeInstance = (BuilderType) this; - mProtoBuilder.setUri(uri).setSchema(schemaType); - // Set current timestamp for creation timestamp by default. - setCreationTimestampMillis(System.currentTimeMillis()); - } - - /** - * Set the score of the {@link Document}. - * - * <p>The score is a query-independent measure of the document's quality, relative to - * other {@link Document}s of the same type. - * - * @throws IllegalArgumentException If the provided value is negative. - * @hide - */ - @NonNull - public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) { - if (score < 0) { - throw new IllegalArgumentException("Document score cannot be negative"); - } - mProtoBuilder.setScore(score); - return mBuilderTypeInstance; - } - - /** - * Set the creation timestamp in milliseconds of the {@link Document}. Should be set - * using a value obtained from the {@link System#currentTimeMillis()} time base. - * - * @hide - */ - @NonNull - public BuilderType setCreationTimestampMillis( - @CurrentTimeMillisLong long creationTimestampMillis) { - mProtoBuilder.setCreationTimestampMs(creationTimestampMillis); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code String} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code String} values of the property. - * @hide - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull String... values) { - putInBundle(mPropertyBundle, key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code boolean} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code boolean} values of the schema.org property. - * @hide - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) { - putInBundle(mPropertyBundle, key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code long} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code long} values of the schema.org property. - * @hide - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull long... values) { - putInBundle(mPropertyBundle, key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code double} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code double} values of the schema.org property. - * @hide - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull double... values) { - putInBundle(mPropertyBundle, key, values); - return mBuilderTypeInstance; - } - - private static void putInBundle( - @NonNull Bundle bundle, @NonNull String key, @NonNull String... values) - throws IllegalArgumentException { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - for (int i = 0; i < values.length; i++) { - if (values[i] == null) { - throw new IllegalArgumentException("The String at " + i + " is null."); - } else if (values[i].length() > MAX_STRING_LENGTH) { - throw new IllegalArgumentException("The String at " + i + " length is: " - + values[i].length() + ", which exceeds length limit: " - + MAX_STRING_LENGTH + "."); - } - } - bundle.putStringArray(key, values); - } - - private static void putInBundle( - @NonNull Bundle bundle, @NonNull String key, @NonNull boolean... values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - bundle.putBooleanArray(key, values); - } - - private static void putInBundle( - @NonNull Bundle bundle, @NonNull String key, @NonNull double... values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - bundle.putDoubleArray(key, values); - } - - private static void putInBundle( - @NonNull Bundle bundle, @NonNull String key, @NonNull long... values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - bundle.putLongArray(key, values); - } - - private static void validateRepeatedPropertyLength(@NonNull String key, int length) { - if (length == 0) { - throw new IllegalArgumentException("The input array is empty."); - } else if (length > MAX_REPEATED_PROPERTY_LENGTH) { - throw new IllegalArgumentException( - "Repeated property \"" + key + "\" has length " + length - + ", which exceeds the limit of " - + MAX_REPEATED_PROPERTY_LENGTH); - } - } - - /** - * Builds the {@link Document} object. - * @hide - */ - public Document build() { - // Build proto by sorting the keys in propertyBundle to exclude the influence of - // order. Therefore documents will generate same proto as long as the contents are - // same. Note that the order of repeated fields is still preserved. - ArrayList<String> keys = new ArrayList<>(mPropertyBundle.keySet()); - Collections.sort(keys); - for (String key : keys) { - Object values = mPropertyBundle.get(key); - PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(key); - if (values instanceof boolean[]) { - for (boolean value : (boolean[]) values) { - propertyProto.addBooleanValues(value); - } - } else if (values instanceof long[]) { - for (long value : (long[]) values) { - propertyProto.addInt64Values(value); - } - } else if (values instanceof double[]) { - for (double value : (double[]) values) { - propertyProto.addDoubleValues(value); - } - } else if (values instanceof String[]) { - for (String value : (String[]) values) { - propertyProto.addStringValues(value); - } - } else { - throw new IllegalStateException( - "Property \"" + key + "\" has unsupported value type \"" - + values.getClass().getSimpleName() + "\""); - } - mProtoBuilder.addProperties(propertyProto); - } - return new Document(mProtoBuilder.build(), mPropertyBundle); - } - } - } - - /** - * Encapsulates a {@link Document} that represent an email. - * - * <p>This class is a higher level implement of {@link Document}. - * - * <p>This class will eventually migrate to Jetpack, where it will become public API. - * - * @hide - */ - public static class Email extends Document { - private static final String KEY_FROM = "from"; - private static final String KEY_TO = "to"; - private static final String KEY_CC = "cc"; - private static final String KEY_BCC = "bcc"; - private static final String KEY_SUBJECT = "subject"; - private static final String KEY_BODY = "body"; - - /** The name of the schema type for {@link Email} documents.*/ - public static final String SCHEMA_TYPE = "builtin:Email"; - - public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE) - .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).build(); - - /** - * Creates a new {@link Email.Builder}. - * - * @param uri The uri of {@link Email}. - */ - public static Builder newBuilder(@NonNull String uri) { - return new Builder(uri); - } - - /** - * Creates a new {@link Email} from the contents of an existing {@link Document}. - * - * @param document The {@link Document} containing the email content. - */ - public Email(@NonNull Document document) { - super(document); - } - - /** - * Get the from address of {@link Email}. - * - * @return Returns the subject of {@link Email} or {@code null} if it's not been set yet. - * @hide - */ - @Nullable - public String getFrom() { - return getPropertyString(KEY_FROM); - } - - /** - * Get the destination addresses of {@link Email}. - * - * @return Returns the destination addresses of {@link Email} or {@code null} if it's not - * been set yet. - * @hide - */ - @Nullable - public String[] getTo() { - return getPropertyStringArray(KEY_TO); - } - - /** - * Get the CC list of {@link Email}. - * - * @return Returns the CC list of {@link Email} or {@code null} if it's not been set yet. - * @hide - */ - @Nullable - public String[] getCc() { - return getPropertyStringArray(KEY_CC); - } - - /** - * Get the BCC list of {@link Email}. - * - * @return Returns the BCC list of {@link Email} or {@code null} if it's not been set yet. - * @hide - */ - @Nullable - public String[] getBcc() { - return getPropertyStringArray(KEY_BCC); - } - - /** - * Get the subject of {@link Email}. - * - * @return Returns the value subject of {@link Email} or {@code null} if it's not been set - * yet. - * @hide - */ - @Nullable - public String getSubject() { - return getPropertyString(KEY_SUBJECT); - } - - /** - * Get the body of {@link Email}. - * - * @return Returns the body of {@link Email} or {@code null} if it's not been set yet. - * @hide - */ - @Nullable - public String getBody() { - return getPropertyString(KEY_BODY); - } - - /** - * The builder class for {@link Email}. - * @hide - */ - public static class Builder extends Document.Builder<Email.Builder> { - - /** - * Create a new {@link Email.Builder} - * @param uri The Uri of the Email. - * @hide - */ - private Builder(@NonNull String uri) { - super(uri, SCHEMA_TYPE); - } - - /** - * Set the from address of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setFrom(@NonNull String from) { - setProperty(KEY_FROM, from); - return this; - } - - /** - * Set the destination address of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setTo(@NonNull String... to) { - setProperty(KEY_TO, to); - return this; - } - - /** - * Set the CC list of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setCc(@NonNull String... cc) { - setProperty(KEY_CC, cc); - return this; - } - - /** - * Set the BCC list of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setBcc(@NonNull String... bcc) { - setProperty(KEY_BCC, bcc); - return this; - } - - /** - * Set the subject of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setSubject(@NonNull String subject) { - setProperty(KEY_SUBJECT, subject); - return this; - } - - /** - * Set the body of {@link Email} - * @hide - */ - @NonNull - public Email.Builder setBody(@NonNull String body) { - setProperty(KEY_BODY, body); - return this; - } - - /** - * Builds the {@link Email} object. - * - * @hide - */ - @NonNull - @Override - public Email build() { - return new Email(super.build()); - } - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java new file mode 100644 index 000000000000..ff0f0dda55b9 --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java @@ -0,0 +1,724 @@ +/* + * 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 android.app.appsearch; + +import android.annotation.CurrentTimeMillisLong; +import android.annotation.DurationMillisLong; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; + +import com.google.android.icing.proto.DocumentProto; +import com.google.android.icing.proto.PropertyProto; +import com.google.android.icing.protobuf.ByteString; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Represents a document unit. + * + * <p>Documents are constructed via {@link AppSearchDocument.Builder}. + * @hide + */ +public class AppSearchDocument { + private static final String TAG = "AppSearchDocument"; + + /** + * The maximum number of elements in a repeatable field. Will reject the request if exceed + * this limit. + */ + private static final int MAX_REPEATED_PROPERTY_LENGTH = 100; + + /** + * The maximum {@link String#length} of a {@link String} field. Will reject the request if + * {@link String}s longer than this. + */ + private static final int MAX_STRING_LENGTH = 20_000; + + /** + * Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and properties + * ordered by keys. + */ + @NonNull + private final DocumentProto mProto; + + /** Contains all properties in {@link #mProto} to support getting properties via keys. */ + @NonNull + private final Map<String, Object> mProperties; + + /** + * Create a new {@link AppSearchDocument}. + * @param proto Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and + * properties ordered by keys. + * @param propertiesMap Contains all properties in {@link #mProto} to support get properties + * via keys. + */ + private AppSearchDocument(@NonNull DocumentProto proto, + @NonNull Map<String, Object> propertiesMap) { + mProto = proto; + mProperties = propertiesMap; + } + + /** + * Create a new {@link AppSearchDocument} from an existing instance. + * + * <p>This method should be only used by constructor of a subclass. + */ + protected AppSearchDocument(@NonNull AppSearchDocument document) { + this(document.mProto, document.mProperties); + } + + /** @hide */ + AppSearchDocument(@NonNull DocumentProto documentProto) { + this(documentProto, new ArrayMap<>()); + for (int i = 0; i < documentProto.getPropertiesCount(); i++) { + PropertyProto property = documentProto.getProperties(i); + String name = property.getName(); + if (property.getStringValuesCount() > 0) { + String[] values = new String[property.getStringValuesCount()]; + for (int j = 0; j < values.length; j++) { + values[j] = property.getStringValues(j); + } + mProperties.put(name, values); + } else if (property.getInt64ValuesCount() > 0) { + long[] values = new long[property.getInt64ValuesCount()]; + for (int j = 0; j < values.length; j++) { + values[j] = property.getInt64Values(j); + } + mProperties.put(property.getName(), values); + } else if (property.getDoubleValuesCount() > 0) { + double[] values = new double[property.getDoubleValuesCount()]; + for (int j = 0; j < values.length; j++) { + values[j] = property.getDoubleValues(j); + } + mProperties.put(property.getName(), values); + } else if (property.getBooleanValuesCount() > 0) { + boolean[] values = new boolean[property.getBooleanValuesCount()]; + for (int j = 0; j < values.length; j++) { + values[j] = property.getBooleanValues(j); + } + mProperties.put(property.getName(), values); + } else if (property.getBytesValuesCount() > 0) { + byte[][] values = new byte[property.getBytesValuesCount()][]; + for (int j = 0; j < values.length; j++) { + values[j] = property.getBytesValues(j).toByteArray(); + } + mProperties.put(name, values); + } else if (property.getDocumentValuesCount() > 0) { + AppSearchDocument[] values = + new AppSearchDocument[property.getDocumentValuesCount()]; + for (int j = 0; j < values.length; j++) { + values[j] = new AppSearchDocument(property.getDocumentValues(j)); + } + mProperties.put(name, values); + } else { + throw new IllegalStateException("Unknown type of value: " + name); + } + } + } + + /** + * Get the {@link DocumentProto} of the {@link AppSearchDocument}. + * + * <p>The {@link DocumentProto} contains {@link AppSearchDocument}'s basic information and all + * properties ordered by keys. + * @hide + */ + @NonNull + @VisibleForTesting + public DocumentProto getProto() { + return mProto; + } + + /** + * Get the uri of the {@link AppSearchDocument}. + * + * @hide + */ + @NonNull + public String getUri() { + return mProto.getUri(); + } + + /** + * Get the schema type of the {@link AppSearchDocument}. + * @hide + */ + @NonNull + public String getSchemaType() { + return mProto.getSchema(); + } + + /** + * Get the creation timestamp in milliseconds of the {@link AppSearchDocument}. Value will be in + * the {@link System#currentTimeMillis()} time base. + * + * @hide + */ + @CurrentTimeMillisLong + public long getCreationTimestampMillis() { + return mProto.getCreationTimestampMs(); + } + + /** + * Returns the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds. + * + * <p>The default value is 0, which means the document is permanent and won't be auto-deleted + * until the app is uninstalled. + * + * @hide + */ + @DurationMillisLong + public long getTtlMillis() { + return mProto.getTtlMs(); + } + + /** + * Returns the score of the {@link AppSearchDocument}. + * + * <p>The score is a query-independent measure of the document's quality, relative to other + * {@link AppSearchDocument}s of the same type. + * + * <p>The default value is 0. + * + * @hide + */ + public int getScore() { + return mProto.getScore(); + } + + /** + * Retrieve a {@link String} value by key. + * + * @param key The key to look for. + * @return The first {@link String} associated with the given key or {@code null} if there + * is no such key or the value is of a different type. + * @hide + */ + @Nullable + public String getPropertyString(@NonNull String key) { + String[] propertyArray = getPropertyStringArray(key); + if (ArrayUtils.isEmpty(propertyArray)) { + return null; + } + warnIfSinglePropertyTooLong("String", key, propertyArray.length); + return propertyArray[0]; + } + + /** + * Retrieve a {@link Long} value by key. + * + * @param key The key to look for. + * @return The first {@link Long} associated with the given key or {@code null} if there + * is no such key or the value is of a different type. + * @hide + */ + @Nullable + public Long getPropertyLong(@NonNull String key) { + long[] propertyArray = getPropertyLongArray(key); + if (ArrayUtils.isEmpty(propertyArray)) { + return null; + } + warnIfSinglePropertyTooLong("Long", key, propertyArray.length); + return propertyArray[0]; + } + + /** + * Retrieve a {@link Double} value by key. + * + * @param key The key to look for. + * @return The first {@link Double} associated with the given key or {@code null} if there + * is no such key or the value is of a different type. + * @hide + */ + @Nullable + public Double getPropertyDouble(@NonNull String key) { + double[] propertyArray = getPropertyDoubleArray(key); + // TODO(tytytyww): Add support double array to ArraysUtils.isEmpty(). + if (propertyArray == null || propertyArray.length == 0) { + return null; + } + warnIfSinglePropertyTooLong("Double", key, propertyArray.length); + return propertyArray[0]; + } + + /** + * Retrieve a {@link Boolean} value by key. + * + * @param key The key to look for. + * @return The first {@link Boolean} associated with the given key or {@code null} if there + * is no such key or the value is of a different type. + * @hide + */ + @Nullable + public Boolean getPropertyBoolean(@NonNull String key) { + boolean[] propertyArray = getPropertyBooleanArray(key); + if (ArrayUtils.isEmpty(propertyArray)) { + return null; + } + warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length); + return propertyArray[0]; + } + + /** + * Retrieve a {@code byte[]} value by key. + * + * @param key The key to look for. + * @return The first {@code byte[]} associated with the given key or {@code null} if there + * is no such key or the value is of a different type. + */ + @Nullable + public byte[] getPropertyBytes(@NonNull String key) { + byte[][] propertyArray = getPropertyBytesArray(key); + if (ArrayUtils.isEmpty(propertyArray)) { + return null; + } + warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length); + return propertyArray[0]; + } + + /** + * Retrieve a {@link AppSearchDocument} value by key. + * + * @param key The key to look for. + * @return The first {@link AppSearchDocument} associated with the given key or {@code null} if + * there is no such key or the value is of a different type. + */ + @Nullable + public AppSearchDocument getPropertyDocument(@NonNull String key) { + AppSearchDocument[] propertyArray = getPropertyDocumentArray(key); + if (ArrayUtils.isEmpty(propertyArray)) { + return null; + } + warnIfSinglePropertyTooLong("Document", key, propertyArray.length); + return propertyArray[0]; + } + + /** Prints a warning to logcat if the given propertyLength is greater than 1. */ + private static void warnIfSinglePropertyTooLong( + @NonNull String propertyType, @NonNull String key, int propertyLength) { + if (propertyLength > 1) { + Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength + + " elements. Only the first one will be returned from " + + "getProperty" + propertyType + "(). Try getProperty" + propertyType + + "Array()."); + } + } + + /** + * Retrieve a repeated {@code String} property by key. + * + * @param key The key to look for. + * @return The {@code String[]} associated with the given key, or {@code null} if no value + * is set or the value is of a different type. + * @hide + */ + @Nullable + public String[] getPropertyStringArray(@NonNull String key) { + return getAndCastPropertyArray(key, String[].class); + } + + /** + * Retrieve a repeated {@code long} property by key. + * + * @param key The key to look for. + * @return The {@code long[]} associated with the given key, or {@code null} if no value is + * set or the value is of a different type. + * @hide + */ + @Nullable + public long[] getPropertyLongArray(@NonNull String key) { + return getAndCastPropertyArray(key, long[].class); + } + + /** + * Retrieve a repeated {@code double} property by key. + * + * @param key The key to look for. + * @return The {@code double[]} associated with the given key, or {@code null} if no value + * is set or the value is of a different type. + * @hide + */ + @Nullable + public double[] getPropertyDoubleArray(@NonNull String key) { + return getAndCastPropertyArray(key, double[].class); + } + + /** + * Retrieve a repeated {@code boolean} property by key. + * + * @param key The key to look for. + * @return The {@code boolean[]} associated with the given key, or {@code null} if no value + * is set or the value is of a different type. + * @hide + */ + @Nullable + public boolean[] getPropertyBooleanArray(@NonNull String key) { + return getAndCastPropertyArray(key, boolean[].class); + } + + /** + * Retrieve a {@code byte[][]} property by key. + * + * @param key The key to look for. + * @return The {@code byte[][]} associated with the given key, or {@code null} if no value + * is set or the value is of a different type. + */ + @Nullable + public byte[][] getPropertyBytesArray(@NonNull String key) { + return getAndCastPropertyArray(key, byte[][].class); + } + + /** + * Retrieve a repeated {@link AppSearchDocument} property by key. + * + * @param key The key to look for. + * @return The {@link AppSearchDocument[]} associated with the given key, or {@code null} if no + * value is set or the value is of a different type. + */ + @Nullable + public AppSearchDocument[] getPropertyDocumentArray(@NonNull String key) { + return getAndCastPropertyArray(key, AppSearchDocument[].class); + } + + /** + * Gets a repeated property of the given key, and casts it to the given class type, which + * must be an array class type. + */ + @Nullable + private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) { + Object value = mProperties.get(key); + if (value == null) { + return null; + } + try { + return tClass.cast(value); + } catch (ClassCastException e) { + Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e); + return null; + } + } + + @Override + public boolean equals(@Nullable Object other) { + // Check only proto's equality is sufficient here since all properties in + // mProperties are ordered by keys and stored in proto. + if (this == other) { + return true; + } + if (!(other instanceof AppSearchDocument)) { + return false; + } + AppSearchDocument otherDocument = (AppSearchDocument) other; + return this.mProto.equals(otherDocument.mProto); + } + + @Override + public int hashCode() { + // Hash only proto is sufficient here since all properties in mProperties are ordered by + // keys and stored in proto. + return mProto.hashCode(); + } + + @Override + public String toString() { + return mProto.toString(); + } + + /** + * The builder class for {@link AppSearchDocument}. + * + * @param <BuilderType> Type of subclass who extend this. + * @hide + */ + public static class Builder<BuilderType extends Builder> { + + private final Map<String, Object> mProperties = new ArrayMap<>(); + private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder(); + private final BuilderType mBuilderTypeInstance; + + /** + * Create a new {@link AppSearchDocument.Builder}. + * + * @param uri The uri of {@link AppSearchDocument}. + * @param schemaType The schema type of the {@link AppSearchDocument}. The passed-in + * {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior + * to inserting a document of this {@code schemaType} into the AppSearch index using + * {@link AppSearchManager#putDocuments(List)}. Otherwise, the document will be + * rejected by {@link AppSearchManager#putDocuments(List)}. + * @hide + */ + public Builder(@NonNull String uri, @NonNull String schemaType) { + mBuilderTypeInstance = (BuilderType) this; + mProtoBuilder.setUri(uri).setSchema(schemaType); + // Set current timestamp for creation timestamp by default. + setCreationTimestampMillis(System.currentTimeMillis()); + } + + /** + * Sets the score of the {@link AppSearchDocument}. + * + * <p>The score is a query-independent measure of the document's quality, relative to + * other {@link AppSearchDocument}s of the same type. + * + * @throws IllegalArgumentException If the provided value is negative. + * @hide + */ + @NonNull + public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) { + if (score < 0) { + throw new IllegalArgumentException("Document score cannot be negative."); + } + mProtoBuilder.setScore(score); + return mBuilderTypeInstance; + } + + /** + * Set the creation timestamp in milliseconds of the {@link AppSearchDocument}. Should be + * set using a value obtained from the {@link System#currentTimeMillis()} time base. + * + * @hide + */ + @NonNull + public BuilderType setCreationTimestampMillis( + @CurrentTimeMillisLong long creationTimestampMillis) { + mProtoBuilder.setCreationTimestampMs(creationTimestampMillis); + return mBuilderTypeInstance; + } + + /** + * Set the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds. + * + * <p>After this many milliseconds since the {@link #setCreationTimestampMillis(long)} + * creation timestamp}, the document is deleted. + * + * @param ttlMillis A non-negative duration in milliseconds. + * @throws IllegalArgumentException If the provided value is negative. + */ + @NonNull + public BuilderType setTtlMillis(@DurationMillisLong long ttlMillis) { + Preconditions.checkArgumentNonNegative( + ttlMillis, "Document ttlMillis cannot be negative."); + mProtoBuilder.setTtlMs(ttlMillis); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@code String} values for a property, replacing its previous + * values. + * + * @param key The key associated with the {@code values}. + * @param values The {@code String} values of the property. + * @hide + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull String... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@code boolean} values for a property, replacing its previous + * values. + * + * @param key The key associated with the {@code values}. + * @param values The {@code boolean} values of the property. + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@code long} values for a property, replacing its previous + * values. + * + * @param key The key associated with the {@code values}. + * @param values The {@code long} values of the property. + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull long... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@code double} values for a property, replacing its previous + * values. + * + * @param key The key associated with the {@code values}. + * @param values The {@code double} values of the property. + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull double... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@code byte[]} for a property, replacing its previous values. + * + * @param key The key associated with the {@code values}. + * @param values The {@code byte[]} of the property. + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + /** + * Sets one or multiple {@link AppSearchDocument} values for a property, replacing its + * previous values. + * + * @param key The key associated with the {@code values}. + * @param values The {@link AppSearchDocument} values of the property. + */ + @NonNull + public BuilderType setProperty(@NonNull String key, @NonNull AppSearchDocument... values) { + putInPropertyMap(key, values); + return mBuilderTypeInstance; + } + + private void putInPropertyMap(@NonNull String key, @NonNull String[] values) + throws IllegalArgumentException { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + validateRepeatedPropertyLength(key, values.length); + for (int i = 0; i < values.length; i++) { + if (values[i] == null) { + throw new IllegalArgumentException("The String at " + i + " is null."); + } else if (values[i].length() > MAX_STRING_LENGTH) { + throw new IllegalArgumentException("The String at " + i + " length is: " + + values[i].length() + ", which exceeds length limit: " + + MAX_STRING_LENGTH + "."); + } + } + mProperties.put(key, values); + } + + private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + validateRepeatedPropertyLength(key, values.length); + mProperties.put(key, values); + } + + private void putInPropertyMap(@NonNull String key, @NonNull double[] values) { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + validateRepeatedPropertyLength(key, values.length); + mProperties.put(key, values); + } + + private void putInPropertyMap(@NonNull String key, @NonNull long[] values) { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + validateRepeatedPropertyLength(key, values.length); + mProperties.put(key, values); + } + + private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + validateRepeatedPropertyLength(key, values.length); + mProperties.put(key, values); + } + + private void putInPropertyMap(@NonNull String key, @NonNull AppSearchDocument[] values) { + Objects.requireNonNull(key); + Objects.requireNonNull(values); + for (int i = 0; i < values.length; i++) { + if (values[i] == null) { + throw new IllegalArgumentException("The document at " + i + " is null."); + } + } + validateRepeatedPropertyLength(key, values.length); + mProperties.put(key, values); + } + + private static void validateRepeatedPropertyLength(@NonNull String key, int length) { + if (length == 0) { + throw new IllegalArgumentException("The input array is empty."); + } else if (length > MAX_REPEATED_PROPERTY_LENGTH) { + throw new IllegalArgumentException( + "Repeated property \"" + key + "\" has length " + length + + ", which exceeds the limit of " + + MAX_REPEATED_PROPERTY_LENGTH); + } + } + + /** + * Builds the {@link AppSearchDocument} object. + * @hide + */ + public AppSearchDocument build() { + // Build proto by sorting the keys in mProperties to exclude the influence of + // order. Therefore documents will generate same proto as long as the contents are + // same. Note that the order of repeated fields is still preserved. + ArrayList<String> keys = new ArrayList<>(mProperties.keySet()); + Collections.sort(keys); + for (int i = 0; i < keys.size(); i++) { + String name = keys.get(i); + Object values = mProperties.get(name); + PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name); + if (values instanceof boolean[]) { + for (boolean value : (boolean[]) values) { + propertyProto.addBooleanValues(value); + } + } else if (values instanceof long[]) { + for (long value : (long[]) values) { + propertyProto.addInt64Values(value); + } + } else if (values instanceof double[]) { + for (double value : (double[]) values) { + propertyProto.addDoubleValues(value); + } + } else if (values instanceof String[]) { + for (String value : (String[]) values) { + propertyProto.addStringValues(value); + } + } else if (values instanceof AppSearchDocument[]) { + for (AppSearchDocument value : (AppSearchDocument[]) values) { + propertyProto.addDocumentValues(value.getProto()); + } + } else if (values instanceof byte[][]) { + for (byte[] value : (byte[][]) values) { + propertyProto.addBytesValues(ByteString.copyFrom(value)); + } + } else { + throw new IllegalStateException( + "Property \"" + name + "\" has unsupported value type \"" + + values.getClass().getSimpleName() + "\""); + } + mProtoBuilder.addProperties(propertyProto); + } + return new AppSearchDocument(mProtoBuilder.build(), mProperties); + } + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java new file mode 100644 index 000000000000..5b9457b77ea0 --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java @@ -0,0 +1,255 @@ +/* + * 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 android.app.appsearch; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.appsearch.AppSearchSchema.PropertyConfig; + +/** + * Encapsulates a {@link AppSearchDocument} that represent an email. + * + * <p>This class is a higher level implement of {@link AppSearchDocument}. + * + * <p>This class will eventually migrate to Jetpack, where it will become public API. + * + * @hide + */ +public class AppSearchEmail extends AppSearchDocument { + private static final String KEY_FROM = "from"; + private static final String KEY_TO = "to"; + private static final String KEY_CC = "cc"; + private static final String KEY_BCC = "bcc"; + private static final String KEY_SUBJECT = "subject"; + private static final String KEY_BODY = "body"; + + /** The name of the schema type for {@link AppSearchEmail} documents.*/ + public static final String SCHEMA_TYPE = "builtin:Email"; + + public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE) + .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_REPEATED) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_REPEATED) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_REPEATED) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY) + .setDataType(PropertyConfig.DATA_TYPE_STRING) + .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) + .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) + .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) + .build() + + ).build(); + + /** + * Creates a new {@link AppSearchEmail} from the contents of an existing + * {@link AppSearchDocument}. + * + * @param document The {@link AppSearchDocument} containing the email content. + */ + public AppSearchEmail(@NonNull AppSearchDocument document) { + super(document); + } + + /** + * Get the from address of {@link AppSearchEmail}. + * + * @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set + * yet. + * @hide + */ + @Nullable + public String getFrom() { + return getPropertyString(KEY_FROM); + } + + /** + * Get the destination addresses of {@link AppSearchEmail}. + * + * @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's + * not been set yet. + * @hide + */ + @Nullable + public String[] getTo() { + return getPropertyStringArray(KEY_TO); + } + + /** + * Get the CC list of {@link AppSearchEmail}. + * + * @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set + * yet. + * @hide + */ + @Nullable + public String[] getCc() { + return getPropertyStringArray(KEY_CC); + } + + /** + * Get the BCC list of {@link AppSearchEmail}. + * + * @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set + * yet. + * @hide + */ + @Nullable + public String[] getBcc() { + return getPropertyStringArray(KEY_BCC); + } + + /** + * Get the subject of {@link AppSearchEmail}. + * + * @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been + * set yet. + * @hide + */ + @Nullable + public String getSubject() { + return getPropertyString(KEY_SUBJECT); + } + + /** + * Get the body of {@link AppSearchEmail}. + * + * @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet. + * @hide + */ + @Nullable + public String getBody() { + return getPropertyString(KEY_BODY); + } + + /** + * The builder class for {@link AppSearchEmail}. + * @hide + */ + public static class Builder extends AppSearchDocument.Builder<AppSearchEmail.Builder> { + + /** + * Create a new {@link AppSearchEmail.Builder} + * @param uri The Uri of the Email. + * @hide + */ + public Builder(@NonNull String uri) { + super(uri, SCHEMA_TYPE); + } + + /** + * Set the from address of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setFrom(@NonNull String from) { + setProperty(KEY_FROM, from); + return this; + } + + /** + * Set the destination address of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setTo(@NonNull String... to) { + setProperty(KEY_TO, to); + return this; + } + + /** + * Set the CC list of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setCc(@NonNull String... cc) { + setProperty(KEY_CC, cc); + return this; + } + + /** + * Set the BCC list of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setBcc(@NonNull String... bcc) { + setProperty(KEY_BCC, bcc); + return this; + } + + /** + * Set the subject of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setSubject(@NonNull String subject) { + setProperty(KEY_SUBJECT, subject); + return this; + } + + /** + * Set the body of {@link AppSearchEmail} + * @hide + */ + @NonNull + public AppSearchEmail.Builder setBody(@NonNull String body) { + setProperty(KEY_BODY, body); + return this; + } + + /** + * Builds the {@link AppSearchEmail} object. + * + * @hide + */ + @NonNull + @Override + public AppSearchEmail build() { + return new AppSearchEmail(super.build()); + } + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java index 15c336820df7..e2c9b0f74870 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -18,7 +18,6 @@ package android.app.appsearch; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.SystemService; -import android.app.appsearch.AppSearch.Document; import android.content.Context; import android.os.RemoteException; @@ -150,25 +149,26 @@ public class AppSearchManager { } /** - * Index {@link android.app.appsearch.AppSearch.Document Documents} into AppSearch. + * Index {@link AppSearchDocument Documents} into AppSearch. * * <p>You should not call this method directly; instead, use the * {@code AppSearch#putDocuments()} API provided by JetPack. * - * <p>Each {@link AppSearch.Document Document's} {@code schemaType} field must be set to the + * <p>Each {@link AppSearchDocument Document's} {@code schemaType} field must be set to the * name of a schema type previously registered via the {@link #setSchema} method. * - * @param documents {@link Document Documents} that need to be indexed. + * @param documents {@link AppSearchDocument Documents} that need to be indexed. * @return An {@link AppSearchBatchResult} mapping the document URIs to {@link Void} if they * were successfully indexed, or a {@link Throwable} describing the failure if they could * not be indexed. * @hide */ - public AppSearchBatchResult<String, Void> putDocuments(@NonNull List<Document> documents) { + public AppSearchBatchResult<String, Void> putDocuments( + @NonNull List<AppSearchDocument> documents) { // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in // one big list. List<byte[]> documentsBytes = new ArrayList<>(documents.size()); - for (Document document : documents) { + for (AppSearchDocument document : documents) { documentsBytes.add(document.getProto().toByteArray()); } AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); diff --git a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java index 6aa91a3fe9e4..5ce296082d70 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java +++ b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java @@ -70,7 +70,7 @@ public final class MatchInfo { private final String mPropertyPath; private final SnippetMatchProto mSnippetMatch; - private final AppSearch.Document mDocument; + private final AppSearchDocument mDocument; /** * List of content with same property path in a document when there are multiple matches in * repeated sections. @@ -79,7 +79,7 @@ public final class MatchInfo { /** @hide */ public MatchInfo(@NonNull String propertyPath, @NonNull SnippetMatchProto snippetMatch, - @NonNull AppSearch.Document document) { + @NonNull AppSearchDocument document) { mPropertyPath = propertyPath; mSnippetMatch = snippetMatch; mDocument = document; diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java index f48ebde288f3..7287fe68f519 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java @@ -71,21 +71,21 @@ public final class SearchResults implements Iterator<SearchResults.Result> { private final SearchResultProto.ResultProto mResultProto; @Nullable - private AppSearch.Document mDocument; + private AppSearchDocument mDocument; private Result(SearchResultProto.ResultProto resultProto) { mResultProto = resultProto; } /** - * Contains the matching {@link AppSearch.Document}. + * Contains the matching {@link AppSearchDocument}. * @return Document object which matched the query. * @hide */ @NonNull - public AppSearch.Document getDocument() { + public AppSearchDocument getDocument() { if (mDocument == null) { - mDocument = new AppSearch.Document(mResultProto.getDocument()); + mDocument = new AppSearchDocument(mResultProto.getDocument()); } return mDocument; } @@ -106,7 +106,7 @@ public final class SearchResults implements Iterator<SearchResults.Result> { if (!mResultProto.hasSnippet()) { return null; } - AppSearch.Document document = getDocument(); + AppSearchDocument document = getDocument(); List<MatchInfo> matchList = new ArrayList<>(); for (Iterator entryProtoIterator = mResultProto.getSnippet() .getEntriesList().iterator(); entryProtoIterator.hasNext(); ) { diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java index 60c313683240..f7e6a987ded3 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java @@ -15,13 +15,26 @@ */ package android.app.blob; +import static android.app.blob.XmlTags.ATTR_ALGO; +import static android.app.blob.XmlTags.ATTR_DIGEST; +import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME; +import static android.app.blob.XmlTags.ATTR_LABEL; +import static android.app.blob.XmlTags.ATTR_TAG; + import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import android.util.Base64; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; import java.util.Arrays; import java.util.Objects; @@ -41,17 +54,20 @@ public final class BlobHandle implements Parcelable { * @hide */ @NonNull public final String algorithm; + /** * Hash of the blob this handle is representing using {@link #algorithm}. * * @hide */ @NonNull public final byte[] digest; + /** * Label of the blob that can be surfaced to the user. * @hide */ @NonNull public final CharSequence label; + /** * Time in milliseconds after which the blob should be invalidated and not * allowed to be accessed by any other app, in {@link System#currentTimeMillis()} timebase. @@ -59,6 +75,7 @@ public final class BlobHandle implements Parcelable { * @hide */ @CurrentTimeMillisLong public final long expiryTimeMillis; + /** * An opaque {@link String} associated with the blob. * @@ -197,6 +214,15 @@ public final class BlobHandle implements Parcelable { return Objects.hash(algorithm, Arrays.hashCode(digest), label, expiryTimeMillis, tag); } + /** @hide */ + public void dump(IndentingPrintWriter fout) { + fout.println("algo: " + algorithm); + fout.println("digest: " + Base64.encodeToString(digest, Base64.NO_WRAP)); + fout.println("label: " + label); + fout.println("expiryMs: " + expiryTimeMillis); + fout.println("tag: " + tag); + } + public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() { @Override public @NonNull BlobHandle createFromParcel(@NonNull Parcel source) { @@ -208,4 +234,25 @@ public final class BlobHandle implements Parcelable { return new BlobHandle[size]; } }; + + /** @hide */ + public void writeToXml(@NonNull XmlSerializer out) throws IOException { + XmlUtils.writeStringAttribute(out, ATTR_ALGO, algorithm); + XmlUtils.writeByteArrayAttribute(out, ATTR_DIGEST, digest); + XmlUtils.writeStringAttribute(out, ATTR_LABEL, label); + XmlUtils.writeLongAttribute(out, ATTR_EXPIRY_TIME, expiryTimeMillis); + XmlUtils.writeStringAttribute(out, ATTR_TAG, tag); + } + + /** @hide */ + @NonNull + public static BlobHandle createFromXml(@NonNull XmlPullParser in) throws IOException { + final String algo = XmlUtils.readStringAttribute(in, ATTR_ALGO); + final byte[] digest = XmlUtils.readByteArrayAttribute(in, ATTR_DIGEST); + final CharSequence label = XmlUtils.readStringAttribute(in, ATTR_LABEL); + final long expiryTimeMs = XmlUtils.readLongAttribute(in, ATTR_EXPIRY_TIME); + final String tag = XmlUtils.readStringAttribute(in, ATTR_TAG); + + return BlobHandle.create(algo, digest, label, expiryTimeMs, tag); + } } diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java index 756bc5ee14c7..8cea645f4e71 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java @@ -25,13 +25,17 @@ import android.annotation.SystemService; import android.content.Context; import android.os.ParcelFileDescriptor; import android.os.ParcelableException; +import android.os.RemoteCallback; import android.os.RemoteException; import com.android.internal.util.function.pooled.PooledLambda; import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; /** @@ -353,6 +357,25 @@ public class BlobStoreManager { } /** + * Wait until any pending tasks (like persisting data to disk) have finished. + * + * @hide + */ + public void waitForIdle(long timeoutMillis) throws InterruptedException, TimeoutException { + try { + final CountDownLatch countDownLatch = new CountDownLatch(1); + mService.waitForIdle(new RemoteCallback((result) -> countDownLatch.countDown())); + if (!countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Timed out waiting for service to become idle"); + } + } catch (ParcelableException e) { + throw new RuntimeException(e); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Represents an ongoing session of a blob's contribution to the blob store managed by the * system. * diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl index dfbf78f4009b..e2128b421746 100644 --- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl +++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl @@ -17,6 +17,7 @@ package android.app.blob; import android.app.blob.BlobHandle; import android.app.blob.IBlobStoreSession; +import android.os.RemoteCallback; /** {@hide} */ interface IBlobStoreManager { @@ -28,4 +29,6 @@ interface IBlobStoreManager { void acquireLease(in BlobHandle handle, int descriptionResId, long leaseTimeout, in String packageName); void releaseLease(in BlobHandle handle, in String packageName); + + void waitForIdle(in RemoteCallback callback); }
\ No newline at end of file diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java new file mode 100644 index 000000000000..803c9a40e5ea --- /dev/null +++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package android.app.blob; + +/** @hide */ +public final class XmlTags { + public static final String ATTR_VERSION = "v"; + + public static final String TAG_SESSIONS = "ss"; + public static final String TAG_BLOBS = "bs"; + + // For BlobStoreSession + public static final String TAG_SESSION = "s"; + public static final String ATTR_ID = "id"; + public static final String ATTR_PACKAGE = "p"; + public static final String ATTR_UID = "u"; + + // For BlobMetadata + public static final String TAG_BLOB = "b"; + public static final String ATTR_USER_ID = "us"; + + // For BlobAccessMode + public static final String TAG_ACCESS_MODE = "am"; + public static final String ATTR_TYPE = "t"; + public static final String TAG_WHITELISTED_PACKAGE = "wl"; + public static final String ATTR_CERTIFICATE = "ct"; + + // For BlobHandle + public static final String TAG_BLOB_HANDLE = "bh"; + public static final String ATTR_ALGO = "al"; + public static final String ATTR_DIGEST = "dg"; + public static final String ATTR_LABEL = "lbl"; + public static final String ATTR_EXPIRY_TIME = "ex"; + public static final String ATTR_TAG = "tg"; + + // For committer + public static final String TAG_COMMITTER = "c"; + + // For leasee + public static final String TAG_LEASEE = "l"; + public static final String ATTR_DESCRIPTION_RES_ID = "rid"; +} diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java index 357250a3244c..ec7ba287acec 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java @@ -15,12 +15,27 @@ */ package com.android.server.blob; +import static android.app.blob.XmlTags.ATTR_CERTIFICATE; +import static android.app.blob.XmlTags.ATTR_PACKAGE; +import static android.app.blob.XmlTags.ATTR_TYPE; +import static android.app.blob.XmlTags.TAG_WHITELISTED_PACKAGE; + import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageManager; import android.util.ArraySet; +import android.util.Base64; +import android.util.DebugUtils; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; @@ -40,10 +55,10 @@ class BlobAccessMode { ACCESS_TYPE_WHITELIST, }) @interface AccessType {} - static final int ACCESS_TYPE_PRIVATE = 1 << 0; - static final int ACCESS_TYPE_PUBLIC = 1 << 1; - static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2; - static final int ACCESS_TYPE_WHITELIST = 1 << 3; + public static final int ACCESS_TYPE_PRIVATE = 1 << 0; + public static final int ACCESS_TYPE_PUBLIC = 1 << 1; + public static final int ACCESS_TYPE_SAME_SIGNATURE = 1 << 2; + public static final int ACCESS_TYPE_WHITELIST = 1 << 3; private int mAccessType = ACCESS_TYPE_PRIVATE; @@ -112,6 +127,51 @@ class BlobAccessMode { return false; } + void dump(IndentingPrintWriter fout) { + fout.println("accessType: " + DebugUtils.flagsToString( + BlobAccessMode.class, "ACCESS_TYPE_", mAccessType)); + fout.print("Whitelisted pkgs:"); + if (mWhitelistedPackages.isEmpty()) { + fout.println(" (Empty)"); + } else { + fout.increaseIndent(); + for (int i = 0, count = mWhitelistedPackages.size(); i < count; ++i) { + fout.println(mWhitelistedPackages.valueAt(i).toString()); + } + fout.decreaseIndent(); + } + } + + void writeToXml(@NonNull XmlSerializer out) throws IOException { + XmlUtils.writeIntAttribute(out, ATTR_TYPE, mAccessType); + for (int i = 0, count = mWhitelistedPackages.size(); i < count; ++i) { + out.startTag(null, TAG_WHITELISTED_PACKAGE); + final PackageIdentifier packageIdentifier = mWhitelistedPackages.valueAt(i); + XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageIdentifier.packageName); + XmlUtils.writeByteArrayAttribute(out, ATTR_CERTIFICATE, packageIdentifier.certificate); + out.endTag(null, TAG_WHITELISTED_PACKAGE); + } + } + + @NonNull + static BlobAccessMode createFromXml(@NonNull XmlPullParser in) + throws IOException, XmlPullParserException { + final BlobAccessMode blobAccessMode = new BlobAccessMode(); + + final int accessType = XmlUtils.readIntAttribute(in, ATTR_TYPE); + blobAccessMode.mAccessType = accessType; + + final int depth = in.getDepth(); + while (XmlUtils.nextElementWithin(in, depth)) { + if (TAG_WHITELISTED_PACKAGE.equals(in.getName())) { + final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); + final byte[] certificate = XmlUtils.readByteArrayAttribute(in, ATTR_CERTIFICATE); + blobAccessMode.allowPackageAccess(packageName, certificate); + } + } + return blobAccessMode; + } + private static final class PackageIdentifier { public final String packageName; public final byte[] certificate; @@ -143,5 +203,11 @@ class BlobAccessMode { public int hashCode() { return Objects.hash(packageName, Arrays.hashCode(certificate)); } + + @Override + public String toString() { + return "[" + packageName + ", " + + Base64.encodeToString(certificate, Base64.NO_WRAP) + "]"; + } } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java index d3a227152627..e9838d6b9712 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -15,20 +15,45 @@ */ package com.android.server.blob; +import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_ID; +import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME; +import static android.app.blob.XmlTags.ATTR_ID; +import static android.app.blob.XmlTags.ATTR_PACKAGE; +import static android.app.blob.XmlTags.ATTR_UID; +import static android.app.blob.XmlTags.ATTR_USER_ID; +import static android.app.blob.XmlTags.TAG_ACCESS_MODE; +import static android.app.blob.XmlTags.TAG_BLOB_HANDLE; +import static android.app.blob.XmlTags.TAG_COMMITTER; +import static android.app.blob.XmlTags.TAG_LEASEE; import static android.system.OsConstants.O_RDONLY; +import static com.android.server.blob.BlobStoreConfig.TAG; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.blob.BlobHandle; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.ParcelFileDescriptor; import android.os.RevocableFileDescriptor; +import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.util.Objects; @@ -37,8 +62,10 @@ class BlobMetadata { private final Object mMetadataLock = new Object(); private final Context mContext; - private final long mBlobId; - private final BlobHandle mBlobHandle; + + public final long blobId; + public final BlobHandle blobHandle; + public final int userId; @GuardedBy("mMetadataLock") private final ArraySet<Committer> mCommitters = new ArraySet<>(); @@ -57,15 +84,47 @@ class BlobMetadata { private final ArrayMap<String, ArraySet<RevocableFileDescriptor>> mRevocableFds = new ArrayMap<>(); - BlobMetadata(Context context, long blobId, BlobHandle blobHandle) { + // Do not access this directly, instead use getSessionFile(). + private File mBlobFile; + + BlobMetadata(Context context, long blobId, BlobHandle blobHandle, int userId) { mContext = context; - mBlobId = blobId; - mBlobHandle = blobHandle; + this.blobId = blobId; + this.blobHandle = blobHandle; + this.userId = userId; + } + + void addCommitter(@NonNull Committer committer) { + synchronized (mMetadataLock) { + mCommitters.add(committer); + } + } + + void addCommitters(ArraySet<Committer> committers) { + synchronized (mMetadataLock) { + mCommitters.addAll(committers); + } + } + + void removeCommitter(@NonNull String packageName, int uid) { + synchronized (mMetadataLock) { + mCommitters.removeIf((committer) -> + committer.uid == uid && committer.packageName.equals(packageName)); + } } - void addCommitter(String packageName, int uid, BlobAccessMode blobAccessMode) { + void removeInvalidCommitters(SparseArray<String> packages) { synchronized (mMetadataLock) { - mCommitters.add(new Committer(packageName, uid, blobAccessMode)); + mCommitters.removeIf(committer -> + !committer.packageName.equals(packages.get(committer.uid))); + } + } + + @Nullable + Committer getExistingCommitter(@NonNull Committer newCommitter) { + synchronized (mCommitters) { + final int index = mCommitters.indexOf(newCommitter); + return index >= 0 ? mCommitters.valueAt(index) : null; } } @@ -77,9 +136,23 @@ class BlobMetadata { } } + void addLeasees(ArraySet<Leasee> leasees) { + synchronized (mMetadataLock) { + mLeasees.addAll(leasees); + } + } + void removeLeasee(String packageName, int uid) { synchronized (mMetadataLock) { - mLeasees.remove(new Accessor(packageName, uid)); + mLeasees.removeIf((leasee) -> + leasee.uid == uid && leasee.packageName.equals(packageName)); + } + } + + void removeInvalidLeasees(SparseArray<String> packages) { + synchronized (mMetadataLock) { + mLeasees.removeIf(leasee -> + !leasee.packageName.equals(packages.get(leasee.uid))); } } @@ -114,11 +187,18 @@ class BlobMetadata { return false; } + File getBlobFile() { + if (mBlobFile == null) { + mBlobFile = BlobStoreConfig.getBlobFile(blobId); + } + return mBlobFile; + } + ParcelFileDescriptor openForRead(String callingPackage) throws IOException { // TODO: Add limit on opened fds FileDescriptor fd; try { - fd = Os.open(BlobStoreConfig.getBlobFile(mBlobId).getPath(), O_RDONLY, 0); + fd = Os.open(getBlobFile().getPath(), O_RDONLY, 0); } catch (ErrnoException e) { throw e.rethrowAsIOException(); } @@ -154,6 +234,94 @@ class BlobMetadata { return revocableFd.getRevocableFileDescriptor(); } + void dump(IndentingPrintWriter fout) { + fout.println("blobHandle:"); + fout.increaseIndent(); + blobHandle.dump(fout); + fout.decreaseIndent(); + + fout.println("Committers:"); + fout.increaseIndent(); + for (int i = 0, count = mCommitters.size(); i < count; ++i) { + final Committer committer = mCommitters.valueAt(i); + fout.println("committer " + committer.toString()); + fout.increaseIndent(); + committer.dump(fout); + fout.decreaseIndent(); + } + fout.decreaseIndent(); + + fout.println("Leasees:"); + fout.increaseIndent(); + for (int i = 0, count = mLeasees.size(); i < count; ++i) { + final Leasee leasee = mLeasees.valueAt(i); + fout.println("leasee " + leasee.toString()); + fout.increaseIndent(); + leasee.dump(mContext, fout); + fout.decreaseIndent(); + } + fout.decreaseIndent(); + + fout.println("Open fds: #" + mRevocableFds.size()); + } + + void writeToXml(XmlSerializer out) throws IOException { + synchronized (mMetadataLock) { + XmlUtils.writeLongAttribute(out, ATTR_ID, blobId); + XmlUtils.writeIntAttribute(out, ATTR_USER_ID, userId); + + out.startTag(null, TAG_BLOB_HANDLE); + blobHandle.writeToXml(out); + out.endTag(null, TAG_BLOB_HANDLE); + + for (int i = 0, count = mCommitters.size(); i < count; ++i) { + out.startTag(null, TAG_COMMITTER); + mCommitters.valueAt(i).writeToXml(out); + out.endTag(null, TAG_COMMITTER); + } + + for (int i = 0, count = mLeasees.size(); i < count; ++i) { + out.startTag(null, TAG_LEASEE); + mLeasees.valueAt(i).writeToXml(out); + out.endTag(null, TAG_LEASEE); + } + } + } + + @Nullable + static BlobMetadata createFromXml(Context context, XmlPullParser in) + throws XmlPullParserException, IOException { + final long blobId = XmlUtils.readLongAttribute(in, ATTR_ID); + final int userId = XmlUtils.readIntAttribute(in, ATTR_USER_ID); + + BlobHandle blobHandle = null; + final ArraySet<Committer> committers = new ArraySet<>(); + final ArraySet<Leasee> leasees = new ArraySet<>(); + final int depth = in.getDepth(); + while (XmlUtils.nextElementWithin(in, depth)) { + if (TAG_BLOB_HANDLE.equals(in.getName())) { + blobHandle = BlobHandle.createFromXml(in); + } else if (TAG_COMMITTER.equals(in.getName())) { + final Committer committer = Committer.createFromXml(in); + if (committer != null) { + committers.add(committer); + } + } else if (TAG_LEASEE.equals(in.getName())) { + leasees.add(Leasee.createFromXml(in)); + } + } + + if (blobHandle == null) { + Slog.wtf(TAG, "blobHandle should be available"); + return null; + } + + final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId); + blobMetadata.addCommitters(committers); + blobMetadata.addLeasees(leasees); + return blobMetadata; + } + static final class Committer extends Accessor { public final BlobAccessMode blobAccessMode; @@ -161,6 +329,42 @@ class BlobMetadata { super(packageName, uid); this.blobAccessMode = blobAccessMode; } + + void dump(IndentingPrintWriter fout) { + fout.println("accessMode:"); + fout.increaseIndent(); + blobAccessMode.dump(fout); + fout.decreaseIndent(); + } + + void writeToXml(@NonNull XmlSerializer out) throws IOException { + XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName); + XmlUtils.writeIntAttribute(out, ATTR_UID, uid); + + out.startTag(null, TAG_ACCESS_MODE); + blobAccessMode.writeToXml(out); + out.endTag(null, TAG_ACCESS_MODE); + } + + @Nullable + static Committer createFromXml(@NonNull XmlPullParser in) + throws XmlPullParserException, IOException { + final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); + final int uid = XmlUtils.readIntAttribute(in, ATTR_UID); + + final int depth = in.getDepth(); + BlobAccessMode blobAccessMode = null; + while (XmlUtils.nextElementWithin(in, depth)) { + if (TAG_ACCESS_MODE.equals(in.getName())) { + blobAccessMode = BlobAccessMode.createFromXml(in); + } + } + if (blobAccessMode == null) { + Slog.wtf(TAG, "blobAccessMode should be available"); + return null; + } + return new Committer(packageName, uid, blobAccessMode); + } } static final class Leasee extends Accessor { @@ -176,6 +380,38 @@ class BlobMetadata { boolean isStillValid() { return expiryTimeMillis == 0 || expiryTimeMillis <= System.currentTimeMillis(); } + + void dump(Context context, IndentingPrintWriter fout) { + String desc = null; + try { + final Resources leaseeRes = context.getPackageManager() + .getResourcesForApplicationAsUser(packageName, UserHandle.getUserId(uid)); + desc = leaseeRes.getString(descriptionResId); + } catch (PackageManager.NameNotFoundException e) { + Slog.d(TAG, "Unknown package in user " + UserHandle.getUserId(uid) + ": " + + packageName, e); + desc = "<none>"; + } + fout.println("desc: " + desc); + fout.println("expiryMs: " + expiryTimeMillis); + } + + void writeToXml(@NonNull XmlSerializer out) throws IOException { + XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName); + XmlUtils.writeIntAttribute(out, ATTR_UID, uid); + XmlUtils.writeIntAttribute(out, ATTR_DESCRIPTION_RES_ID, descriptionResId); + XmlUtils.writeLongAttribute(out, ATTR_EXPIRY_TIME, expiryTimeMillis); + } + + @NonNull + static Leasee createFromXml(@NonNull XmlPullParser in) throws IOException { + final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); + final int uid = XmlUtils.readIntAttribute(in, ATTR_UID); + final int descriptionResId = XmlUtils.readIntAttribute(in, ATTR_DESCRIPTION_RES_ID); + final long expiryTimeMillis = XmlUtils.readLongAttribute(in, ATTR_EXPIRY_TIME); + + return new Leasee(packageName, uid, descriptionResId, expiryTimeMillis); + } } static class Accessor { @@ -207,5 +443,10 @@ class BlobMetadata { public int hashCode() { return Objects.hash(packageName, uid); } + + @Override + public String toString() { + return "[" + packageName + ", " + uid + "]"; + } } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java index b9a4b17c53cc..eb414b0f11a6 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java @@ -25,6 +25,13 @@ import java.io.File; class BlobStoreConfig { public static final String TAG = "BlobStore"; + public static final int CURRENT_XML_VERSION = 1; + + private static final String ROOT_DIR_NAME = "blobstore"; + private static final String BLOBS_DIR_NAME = "blobs"; + private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml"; + private static final String BLOBS_INDEX_FILE_NAME = "blobs_index.xml"; + @Nullable public static File prepareBlobFile(long sessionId) { final File blobsDir = prepareBlobsDir(); @@ -58,7 +65,25 @@ class BlobStoreConfig { @NonNull private static File getBlobsDir(File blobsRootDir) { - return new File(blobsRootDir, "blobs"); + return new File(blobsRootDir, BLOBS_DIR_NAME); + } + + @Nullable + public static File prepareSessionIndexFile() { + final File blobStoreRootDir = prepareBlobStoreRootDir(); + if (blobStoreRootDir == null) { + return null; + } + return new File(blobStoreRootDir, SESSIONS_INDEX_FILE_NAME); + } + + @Nullable + public static File prepareBlobsIndexFile() { + final File blobsStoreRootDir = prepareBlobStoreRootDir(); + if (blobsStoreRootDir == null) { + return null; + } + return new File(blobsStoreRootDir, BLOBS_INDEX_FILE_NAME); } @Nullable @@ -73,6 +98,6 @@ class BlobStoreConfig { @NonNull public static File getBlobStoreRootDir() { - return new File(Environment.getDataSystemDirectory(), "blobstore"); + return new File(Environment.getDataSystemDirectory(), ROOT_DIR_NAME); } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 9d60f861e8eb..fcc30e30dfaa 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -15,8 +15,19 @@ */ package com.android.server.blob; +import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR; import static android.app.blob.BlobStoreManager.COMMIT_RESULT_SUCCESS; - +import static android.app.blob.XmlTags.ATTR_VERSION; +import static android.app.blob.XmlTags.TAG_BLOB; +import static android.app.blob.XmlTags.TAG_BLOBS; +import static android.app.blob.XmlTags.TAG_SESSION; +import static android.app.blob.XmlTags.TAG_SESSIONS; +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.MATCH_UNINSTALLED_PACKAGES; +import static android.os.UserHandle.USER_NULL; + +import static com.android.server.blob.BlobStoreConfig.CURRENT_XML_VERSION; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED; import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED; @@ -28,32 +39,58 @@ import android.annotation.CurrentTimeSecondsLong; import android.annotation.IdRes; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.blob.BlobHandle; import android.app.blob.IBlobStoreManager; import android.app.blob.IBlobStoreSession; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.RemoteCallback; +import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManagerInternal; import android.util.ArrayMap; +import android.util.AtomicFile; import android.util.ExceptionUtils; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; +import android.util.Xml; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.Watchdog; +import com.android.server.blob.BlobMetadata.Committer; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlSerializer; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; /** * Service responsible for maintaining and facilitating access to data blobs published by apps. @@ -96,14 +133,34 @@ public class BlobStoreManagerService extends SystemService { publishBinderService(Context.BLOB_STORE_SERVICE, new Stub()); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + registerReceivers(); } + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + synchronized (mBlobsLock) { + final SparseArray<SparseArray<String>> allPackages = getAllPackages(); + readBlobSessionsLocked(allPackages); + readBlobsInfoLocked(allPackages); + } + } + } @GuardedBy("mBlobsLock") private long generateNextSessionIdLocked() { return ++mCurrentMaxSessionId; } + private void registerReceivers() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL, + intentFilter, null, mHandler); + } + @GuardedBy("mBlobsLock") private LongSparseArray<BlobStoreSession> getUserSessionsLocked(int userId) { LongSparseArray<BlobStoreSession> userSessions = mSessions.get(userId); @@ -133,7 +190,7 @@ public class BlobStoreManagerService extends SystemService { sessionId, blobHandle, callingUid, callingPackage, mSessionStateChangeListener); getUserSessionsLocked(UserHandle.getUserId(callingUid)).put(sessionId, session); - // TODO: persist sessions data + writeBlobSessionsAsync(); return sessionId; } } @@ -160,7 +217,8 @@ public class BlobStoreManagerService extends SystemService { callingUid, callingPackage); session.open(); session.abandon(); - // TODO: persist sessions data + + writeBlobSessionsAsync(); } } @@ -194,7 +252,7 @@ public class BlobStoreManagerService extends SystemService { } blobMetadata.addLeasee(callingPackage, callingUid, descriptionResId, leaseExpiryTimeMillis); - // TODO: persist blobs data + writeBlobsInfoAsync(); } } @@ -209,6 +267,7 @@ public class BlobStoreManagerService extends SystemService { + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage); } blobMetadata.removeLeasee(callingPackage, callingUid); + writeBlobsInfoAsync(); } } @@ -241,18 +300,25 @@ public class BlobStoreManagerService extends SystemService { session.verifyBlobData(); break; case STATE_VERIFIED_VALID: - final ArrayMap<BlobHandle, BlobMetadata> userBlobs = - getUserBlobsLocked(UserHandle.getUserId(session.ownerUid)); + final int userId = UserHandle.getUserId(session.ownerUid); + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId); BlobMetadata blob = userBlobs.get(session.blobHandle); if (blob == null) { blob = new BlobMetadata(mContext, - session.sessionId, session.blobHandle); + session.sessionId, session.blobHandle, userId); userBlobs.put(session.blobHandle, blob); } - blob.addCommitter(session.ownerPackageName, session.ownerUid, - session.getBlobAccessMode()); - // TODO: Persist blobs data. - session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS); + final Committer newCommitter = new Committer(session.ownerPackageName, + session.ownerUid, session.getBlobAccessMode()); + final Committer existingCommitter = blob.getExistingCommitter(newCommitter); + blob.addCommitter(newCommitter); + try { + writeBlobsInfoLocked(); + session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS); + } catch (Exception e) { + blob.addCommitter(existingCommitter); + session.sendCommitCallbackResult(COMMIT_RESULT_ERROR); + } getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)) .remove(session.sessionId); break; @@ -260,7 +326,330 @@ public class BlobStoreManagerService extends SystemService { Slog.wtf(TAG, "Invalid session state: " + stateToString(session.getState())); } - // TODO: Persist sessions data. + try { + writeBlobSessionsLocked(); + } catch (Exception e) { + // already logged, ignore. + } + } + } + + @GuardedBy("mBlobsLock") + private void writeBlobSessionsLocked() throws Exception { + final AtomicFile sessionsIndexFile = prepareSessionsIndexFile(); + if (sessionsIndexFile == null) { + Slog.wtf(TAG, "Error creating sessions index file"); + return; + } + FileOutputStream fos = null; + try { + fos = sessionsIndexFile.startWrite(SystemClock.uptimeMillis()); + final XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, StandardCharsets.UTF_8.name()); + out.startDocument(null, true); + out.startTag(null, TAG_SESSIONS); + XmlUtils.writeIntAttribute(out, ATTR_VERSION, CURRENT_XML_VERSION); + + for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) { + final LongSparseArray<BlobStoreSession> userSessions = + mSessions.valueAt(i); + for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) { + out.startTag(null, TAG_SESSION); + userSessions.valueAt(j).writeToXml(out); + out.endTag(null, TAG_SESSION); + } + } + + out.endTag(null, TAG_SESSIONS); + out.endDocument(); + sessionsIndexFile.finishWrite(fos); + } catch (Exception e) { + sessionsIndexFile.failWrite(fos); + Slog.wtf(TAG, "Error writing sessions data", e); + throw e; + } + } + + @GuardedBy("mBlobsLock") + private void readBlobSessionsLocked(SparseArray<SparseArray<String>> allPackages) { + if (!BlobStoreConfig.getBlobStoreRootDir().exists()) { + return; + } + final AtomicFile sessionsIndexFile = prepareSessionsIndexFile(); + if (sessionsIndexFile == null) { + Slog.wtf(TAG, "Error creating sessions index file"); + return; + } + + mSessions.clear(); + try (FileInputStream fis = sessionsIndexFile.openRead()) { + final XmlPullParser in = Xml.newPullParser(); + in.setInput(fis, StandardCharsets.UTF_8.name()); + XmlUtils.beginDocument(in, TAG_SESSIONS); + while (true) { + XmlUtils.nextElement(in); + if (in.getEventType() == XmlPullParser.END_DOCUMENT) { + break; + } + + if (TAG_SESSION.equals(in.getName())) { + final BlobStoreSession session = BlobStoreSession.createFromXml( + in, mContext, mSessionStateChangeListener); + if (session == null) { + continue; + } + final SparseArray<String> userPackages = allPackages.get( + UserHandle.getUserId(session.ownerUid)); + if (userPackages != null + && session.ownerPackageName.equals( + userPackages.get(session.ownerUid))) { + getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)).put( + session.sessionId, session); + } else { + // Unknown package or the session data does not belong to this package. + session.getSessionFile().delete(); + } + mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.sessionId); + } + } + } catch (Exception e) { + Slog.wtf(TAG, "Error reading sessions data", e); + } + } + + @GuardedBy("mBlobsLock") + private void writeBlobsInfoLocked() throws Exception { + final AtomicFile blobsIndexFile = prepareBlobsIndexFile(); + if (blobsIndexFile == null) { + Slog.wtf(TAG, "Error creating blobs index file"); + return; + } + FileOutputStream fos = null; + try { + fos = blobsIndexFile.startWrite(SystemClock.uptimeMillis()); + final XmlSerializer out = new FastXmlSerializer(); + out.setOutput(fos, StandardCharsets.UTF_8.name()); + out.startDocument(null, true); + out.startTag(null, TAG_BLOBS); + XmlUtils.writeIntAttribute(out, ATTR_VERSION, CURRENT_XML_VERSION); + + for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) { + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i); + for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) { + out.startTag(null, TAG_BLOB); + userBlobs.valueAt(j).writeToXml(out); + out.endTag(null, TAG_BLOB); + } + } + + out.endTag(null, TAG_BLOBS); + out.endDocument(); + blobsIndexFile.finishWrite(fos); + } catch (Exception e) { + blobsIndexFile.failWrite(fos); + Slog.wtf(TAG, "Error writing blobs data", e); + throw e; + } + } + + @GuardedBy("mBlobsLock") + private void readBlobsInfoLocked(SparseArray<SparseArray<String>> allPackages) { + if (!BlobStoreConfig.getBlobStoreRootDir().exists()) { + return; + } + final AtomicFile blobsIndexFile = prepareBlobsIndexFile(); + if (blobsIndexFile == null) { + Slog.wtf(TAG, "Error creating blobs index file"); + return; + } + + mBlobsMap.clear(); + try (FileInputStream fis = blobsIndexFile.openRead()) { + final XmlPullParser in = Xml.newPullParser(); + in.setInput(fis, StandardCharsets.UTF_8.name()); + XmlUtils.beginDocument(in, TAG_BLOBS); + while (true) { + XmlUtils.nextElement(in); + if (in.getEventType() == XmlPullParser.END_DOCUMENT) { + break; + } + + if (TAG_BLOB.equals(in.getName())) { + final BlobMetadata blobMetadata = BlobMetadata.createFromXml(mContext, in); + final SparseArray<String> userPackages = allPackages.get(blobMetadata.userId); + if (userPackages == null) { + blobMetadata.getBlobFile().delete(); + } else { + getUserBlobsLocked(blobMetadata.userId).put( + blobMetadata.blobHandle, blobMetadata); + blobMetadata.removeInvalidCommitters(userPackages); + blobMetadata.removeInvalidLeasees(userPackages); + } + mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, blobMetadata.blobId); + } + } + } catch (Exception e) { + Slog.wtf(TAG, "Error reading blobs data", e); + } + } + + private void writeBlobsInfo() { + synchronized (mBlobsLock) { + try { + writeBlobsInfoLocked(); + } catch (Exception e) { + // Already logged, ignore + } + } + } + + private void writeBlobsInfoAsync() { + mHandler.post(PooledLambda.obtainRunnable( + BlobStoreManagerService::writeBlobsInfo, + BlobStoreManagerService.this).recycleOnUse()); + } + + private void writeBlobSessions() { + synchronized (mBlobsLock) { + try { + writeBlobSessionsLocked(); + } catch (Exception e) { + // Already logged, ignore + } + } + } + + private void writeBlobSessionsAsync() { + mHandler.post(PooledLambda.obtainRunnable( + BlobStoreManagerService::writeBlobSessions, + BlobStoreManagerService.this).recycleOnUse()); + } + + private int getPackageUid(String packageName, int userId) { + final int uid = mPackageManagerInternal.getPackageUid( + packageName, + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_UNINSTALLED_PACKAGES, + userId); + return uid; + } + + private SparseArray<SparseArray<String>> getAllPackages() { + final SparseArray<SparseArray<String>> allPackages = new SparseArray<>(); + final int[] allUsers = LocalServices.getService(UserManagerInternal.class).getUserIds(); + for (int userId : allUsers) { + final SparseArray<String> userPackages = new SparseArray<>(); + allPackages.put(userId, userPackages); + final List<ApplicationInfo> applicationInfos = mPackageManagerInternal + .getInstalledApplications( + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE + | MATCH_UNINSTALLED_PACKAGES, + userId, Process.myUid()); + for (int i = 0, count = applicationInfos.size(); i < count; ++i) { + final ApplicationInfo applicationInfo = applicationInfos.get(i); + userPackages.put(applicationInfo.uid, applicationInfo.packageName); + } + } + return allPackages; + } + + AtomicFile prepareSessionsIndexFile() { + final File file = BlobStoreConfig.prepareSessionIndexFile(); + if (file == null) { + return null; + } + return new AtomicFile(file, "session_index" /* commitLogTag */); + } + + AtomicFile prepareBlobsIndexFile() { + final File file = BlobStoreConfig.prepareBlobsIndexFile(); + if (file == null) { + return null; + } + return new AtomicFile(file, "blobs_index" /* commitLogTag */); + } + + private void handlePackageRemoved(String packageName, int uid) { + synchronized (mBlobsLock) { + // Clean up any pending sessions + final LongSparseArray<BlobStoreSession> userSessions = + getUserSessionsLocked(UserHandle.getUserId(uid)); + final ArrayList<Integer> indicesToRemove = new ArrayList<>(); + for (int i = 0, count = userSessions.size(); i < count; ++i) { + final BlobStoreSession session = userSessions.valueAt(i); + if (session.ownerUid == uid + && session.ownerPackageName.equals(packageName)) { + session.getSessionFile().delete(); + indicesToRemove.add(i); + } + } + for (int i = 0, count = indicesToRemove.size(); i < count; ++i) { + userSessions.removeAt(i); + } + + // Remove the package from the committer and leasee list + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = + getUserBlobsLocked(UserHandle.getUserId(uid)); + for (int i = 0, count = userBlobs.size(); i < count; ++i) { + final BlobMetadata blobMetadata = userBlobs.valueAt(i); + blobMetadata.removeCommitter(packageName, uid); + blobMetadata.removeLeasee(packageName, uid); + } + // TODO: clean-up blobs which doesn't have any active leases. + } + } + + private void handleUserRemoved(int userId) { + synchronized (mBlobsLock) { + final LongSparseArray<BlobStoreSession> userSessions = + mSessions.removeReturnOld(userId); + if (userSessions != null) { + for (int i = 0, count = userSessions.size(); i < count; ++i) { + final BlobStoreSession session = userSessions.valueAt(i); + session.getSessionFile().delete(); + } + } + + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = + mBlobsMap.removeReturnOld(userId); + if (userBlobs != null) { + for (int i = 0, count = userBlobs.size(); i < count; ++i) { + final BlobMetadata blobMetadata = userBlobs.valueAt(i); + blobMetadata.getBlobFile().delete(); + } + } + } + } + + private class PackageChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + final String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName == null) { + Slog.wtf(TAG, "Package name is missing in the intent: " + intent); + return; + } + final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (uid == -1) { + Slog.wtf(TAG, "uid is missing in the intent: " + intent); + return; + } + handlePackageRemoved(packageName, uid); + break; + case Intent.ACTION_USER_REMOVED: + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + USER_NULL); + if (userId == USER_NULL) { + Slog.wtf(TAG, "userId is missing in the intent: " + intent); + return; + } + handleUserRemoved(userId); + break; + default: + Slog.wtf(TAG, "Received unknown intent: " + intent); + } } } @@ -341,6 +730,8 @@ public class BlobStoreManagerService extends SystemService { @CurrentTimeSecondsLong long leaseTimeoutSecs, @NonNull String packageName) { Preconditions.checkNotNull(blobHandle, "blobHandle must not be null"); Preconditions.checkNotNull(packageName, "packageName must not be null"); + Preconditions.checkArgumentPositive(descriptionResId, + "descriptionResId must be positive; value=" + descriptionResId); final int callingUid = Binder.getCallingUid(); verifyCallingPackage(callingUid, packageName); @@ -360,5 +751,62 @@ public class BlobStoreManagerService extends SystemService { releaseLeaseInternal(blobHandle, callingUid, packageName); } + + @Override + public void waitForIdle(@NonNull RemoteCallback remoteCallback) { + Preconditions.checkNotNull(remoteCallback, "remoteCallback must not be null"); + + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, + "Caller is not allowed to call this; caller=" + Binder.getCallingUid()); + mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null) + .recycleOnUse()); + } + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, + @Nullable String[] args) { + // TODO: add proto-based version of this. + if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; + + final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " "); + synchronized (mBlobsLock) { + fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId); + fout.println(); + for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) { + final int userId = mSessions.keyAt(i); + final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i); + fout.println("List of sessions in user #" + + userId + " (" + userSessions.size() + "):"); + fout.increaseIndent(); + for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) { + final long sessionId = userSessions.keyAt(j); + final BlobStoreSession session = userSessions.valueAt(j); + fout.println("Session #" + sessionId); + fout.increaseIndent(); + session.dump(fout); + fout.decreaseIndent(); + } + fout.decreaseIndent(); + } + + fout.print("\n\n"); + + for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) { + final int userId = mBlobsMap.keyAt(i); + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i); + fout.println("List of blobs in user #" + + userId + " (" + userBlobs.size() + "):"); + fout.increaseIndent(); + for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) { + final BlobMetadata blobMetadata = userBlobs.valueAt(j); + fout.println("Blob #" + blobMetadata.blobId); + fout.increaseIndent(); + blobMetadata.dump(fout); + fout.decreaseIndent(); + } + fout.decreaseIndent(); + } + } + } } -} +}
\ No newline at end of file diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java index 612fd89ebbe0..7d1c16653383 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java @@ -16,6 +16,11 @@ package com.android.server.blob; import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR; +import static android.app.blob.XmlTags.ATTR_ID; +import static android.app.blob.XmlTags.ATTR_PACKAGE; +import static android.app.blob.XmlTags.ATTR_UID; +import static android.app.blob.XmlTags.TAG_ACCESS_MODE; +import static android.app.blob.XmlTags.TAG_BLOB_HANDLE; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_RDWR; @@ -42,9 +47,15 @@ import android.util.ExceptionUtils; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -224,7 +235,7 @@ public class BlobStoreSession extends IBlobStoreSession.Stub { @Override @BytesLong public long getSize() { - return 0; + return getSessionFile().length(); } @Override @@ -366,8 +377,8 @@ public class BlobStoreSession extends IBlobStoreSession.Stub { private void revokeAllFdsLocked() { for (int i = mRevocableFds.size() - 1; i >= 0; --i) { mRevocableFds.get(i).revoke(); - mRevocableFds.remove(i); } + mRevocableFds.clear(); } @GuardedBy("mSessionLock") @@ -418,4 +429,74 @@ public class BlobStoreSession extends IBlobStoreSession.Stub { throw new SecurityException(ownerUid + " is not the session owner"); } } + + void dump(IndentingPrintWriter fout) { + synchronized (mSessionLock) { + fout.println("state: " + stateToString(mState)); + fout.println("ownerUid: " + ownerUid); + fout.println("ownerPkg: " + ownerPackageName); + + fout.println("blobHandle:"); + fout.increaseIndent(); + blobHandle.dump(fout); + fout.decreaseIndent(); + + fout.println("accessMode:"); + fout.increaseIndent(); + mBlobAccessMode.dump(fout); + fout.decreaseIndent(); + + fout.println("Open fds: #" + mRevocableFds.size()); + } + } + + void writeToXml(@NonNull XmlSerializer out) throws IOException { + synchronized (mSessionLock) { + XmlUtils.writeLongAttribute(out, ATTR_ID, sessionId); + XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, ownerPackageName); + XmlUtils.writeIntAttribute(out, ATTR_UID, ownerUid); + + out.startTag(null, TAG_BLOB_HANDLE); + blobHandle.writeToXml(out); + out.endTag(null, TAG_BLOB_HANDLE); + + out.startTag(null, TAG_ACCESS_MODE); + mBlobAccessMode.writeToXml(out); + out.endTag(null, TAG_ACCESS_MODE); + } + } + + @Nullable + static BlobStoreSession createFromXml(@NonNull XmlPullParser in, + @NonNull Context context, @NonNull SessionStateChangeListener stateChangeListener) + throws IOException, XmlPullParserException { + final int sessionId = XmlUtils.readIntAttribute(in, ATTR_ID); + final String ownerPackageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); + final int ownerUid = XmlUtils.readIntAttribute(in, ATTR_UID); + + final int depth = in.getDepth(); + BlobHandle blobHandle = null; + BlobAccessMode blobAccessMode = null; + while (XmlUtils.nextElementWithin(in, depth)) { + if (TAG_BLOB_HANDLE.equals(in.getName())) { + blobHandle = BlobHandle.createFromXml(in); + } else if (TAG_ACCESS_MODE.equals(in.getName())) { + blobAccessMode = BlobAccessMode.createFromXml(in); + } + } + + if (blobHandle == null) { + Slog.wtf(TAG, "blobHandle should be available"); + return null; + } + if (blobAccessMode == null) { + Slog.wtf(TAG, "blobAccessMode should be available"); + return null; + } + + final BlobStoreSession blobStoreSession = new BlobStoreSession(context, sessionId, + blobHandle, ownerUid, ownerPackageName, stateChangeListener); + blobStoreSession.mBlobAccessMode.allow(blobAccessMode); + return blobStoreSession; + } } 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 a0e83daf877d..bb94275fc409 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 @@ -144,14 +144,18 @@ public final class ConnectivityController extends RestrictingController implemen public void startTrackingRestrictedJobLocked(JobStatus jobStatus) { // Don't need to start tracking the job. If the job needed network, it would already be // tracked. - updateConstraintsSatisfied(jobStatus); + if (jobStatus.hasConnectivityConstraint()) { + updateConstraintsSatisfied(jobStatus); + } } @Override public void stopTrackingRestrictedJobLocked(JobStatus jobStatus) { // Shouldn't stop tracking the job here. If the job was tracked, it still needs network, // even after being unrestricted. - updateConstraintsSatisfied(jobStatus); + if (jobStatus.hasConnectivityConstraint()) { + updateConstraintsSatisfied(jobStatus); + } } /** diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index ac66d1b7f4ad..d59270c6a51b 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -223,7 +223,7 @@ public final class MediaParser { public static final class SeekPoint { /** A {@link SeekPoint} whose time and byte offset are both set to 0. */ - public static final @NonNull SeekPoint START = new SeekPoint(0, 0); + @NonNull public static final SeekPoint START = new SeekPoint(0, 0); /** The time of the seek point, in microseconds. */ public final long timeUs; @@ -241,7 +241,8 @@ public final class MediaParser { } @Override - public @NonNull String toString() { + @NonNull + public String toString() { return "[timeUs=" + timeUs + ", position=" + position + "]"; } @@ -414,7 +415,8 @@ public final class MediaParser { * @return A new instance. * @throws IllegalArgumentException If an invalid name is provided. */ - public static @NonNull MediaParser createByName( + @NonNull + public static MediaParser createByName( @NonNull String name, @NonNull OutputConsumer outputConsumer) { String[] nameAsArray = new String[] {name}; assertValidNames(nameAsArray); @@ -431,7 +433,8 @@ public final class MediaParser { * default array of names is used. * @return A new instance. */ - public static @NonNull MediaParser create( + @NonNull + public static MediaParser create( @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) { assertValidNames(extractorNames); if (extractorNames.length == 0) { @@ -448,7 +451,8 @@ public final class MediaParser { * * <p>TODO: List which properties are taken into account. E.g. MimeType. */ - public static @NonNull List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) { + @NonNull + public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) { throw new UnsupportedOperationException(); } @@ -479,7 +483,8 @@ public final class MediaParser { * @return The name of the backing extractor implementation, or null if the backing extractor * implementation has not yet been selected. */ - public @Nullable String getExtractorName() { + @Nullable + public String getExtractorName() { return mExtractorName; } diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp index dd174734df6d..245a96b99148 100644 --- a/apex/sdkextensions/framework/Android.bp +++ b/apex/sdkextensions/framework/Android.bp @@ -32,6 +32,7 @@ java_library { libs: [ "framework-annotations-lib" ], permitted_packages: [ "android.os.ext" ], installable: true, + plugins: ["java_api_finder"], visibility: [ "//frameworks/base/apex/sdkextensions", "//frameworks/base/apex/sdkextensions/testing", diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp index cc5172c6018a..6d639fddd043 100644 --- a/apex/statsd/aidl/Android.bp +++ b/apex/statsd/aidl/Android.bp @@ -14,7 +14,7 @@ // limitations under the License. // -// TODO(b/145815909): move StatsDimensionsValue.aidl and StatsLogEventWrapper.aidl here +// TODO(b/145815909): move StatsDimensionsValue.aidl here filegroup { name: "statsd_aidl", srcs: [ diff --git a/api/current.txt b/api/current.txt index af4cbd10eb38..b6d67ab412ca 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2873,6 +2873,8 @@ package android.accessibilityservice { method public final boolean performGlobalAction(int); method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>); + field public static final int GESTURE_DOUBLE_TAP = 17; // 0x11 + field public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; // 0x12 field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2 field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15; // 0xf field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16; // 0x10 @@ -2986,9 +2988,11 @@ package android.accessibilityservice { field @Deprecated public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8 field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20 field public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 512; // 0x200 + field public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 4096; // 0x1000 field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400 field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4 field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40 + field public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 2048; // 0x800 field public int eventTypes; field public int feedbackType; field public int flags; @@ -3901,6 +3905,7 @@ package android.app { method public void setImmersive(boolean); method public void setInheritShowWhenLocked(boolean); method public void setIntent(android.content.Intent); + method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle); method public final void setMediaController(android.media.session.MediaController); method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams); method @Deprecated public final void setProgress(int); @@ -6918,6 +6923,7 @@ package android.app.admin { method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int); method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); method public boolean requestBugreport(@NonNull android.content.ComponentName); + method public void requestSetLocationProviderAllowed(@NonNull android.content.ComponentName, @NonNull String, boolean); method @Deprecated public boolean resetPassword(String, int); method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int); method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long); @@ -10167,6 +10173,7 @@ package android.content { field public static final String STORAGE_STATS_SERVICE = "storagestats"; field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth"; field public static final String TELECOM_SERVICE = "telecom"; + field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TELEPHONY_SERVICE = "phone"; field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service"; field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification"; @@ -12068,6 +12075,7 @@ package android.content.pm { field public static final String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope"; field public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate"; field public static final String FEATURE_SENSOR_HEART_RATE_ECG = "android.hardware.sensor.heartrate.ecg"; + field public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle"; field public static final String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light"; field public static final String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity"; field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity"; @@ -30053,6 +30061,7 @@ package android.net { method public int getLinkDownstreamBandwidthKbps(); method public int getLinkUpstreamBandwidthKbps(); method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); + method public int getOwnerUid(); method public int getSignalStrength(); method @Nullable public android.net.TransportInfo getTransportInfo(); method public boolean hasCapability(int); @@ -30062,6 +30071,7 @@ package android.net { method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier); + method public void setOwnerUid(int); method @NonNull public android.net.NetworkCapabilities setSignalStrength(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR; @@ -45732,6 +45742,9 @@ package android.telecom { field public static final int MISSED = 5; // 0x5 field public static final int OTHER = 9; // 0x9 field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED"; + field public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL"; + field public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED"; + field public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF"; field public static final int REJECTED = 6; // 0x6 field public static final int REMOTE = 3; // 0x3 field public static final int RESTRICTED = 8; // 0x8 @@ -46060,6 +46073,7 @@ package android.telecom { field public static final int DURATION_SHORT = 1; // 0x1 field public static final int DURATION_VERY_SHORT = 0; // 0x0 field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"; + field public static final String EXTRA_CALL_CREATED_TIME_MILLIS = "android.telecom.extra.CALL_CREATED_TIME_MILLIS"; field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"; field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION"; @@ -48244,13 +48258,20 @@ package android.telephony.ims { public final class ImsException extends java.lang.Exception { method public int getCode(); + field public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; // 0x3 field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } + public class ImsManager { + method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); + field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; + } + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting(); @@ -56148,6 +56169,7 @@ package android.view.contentcapture { method public boolean isContentCaptureEnabled(); method public void removeData(@NonNull android.view.contentcapture.DataRemovalRequest); method public void setContentCaptureEnabled(boolean); + method public void shareData(@NonNull android.view.contentcapture.DataShareRequest, @NonNull java.util.concurrent.Executor, @NonNull android.view.contentcapture.DataShareWriteAdapter); } public abstract class ContentCaptureSession implements java.lang.AutoCloseable { @@ -56196,6 +56218,24 @@ package android.view.contentcapture { method @NonNull public android.content.LocusId getLocusId(); } + public final class DataShareRequest implements android.os.Parcelable { + ctor public DataShareRequest(@Nullable android.content.LocusId, @NonNull String); + method public int describeContents(); + method @Nullable public android.content.LocusId getLocusId(); + method @NonNull public String getMimeType(); + method @NonNull public String getPackageName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.DataShareRequest> CREATOR; + } + + public interface DataShareWriteAdapter { + method public default void onError(int); + method public void onRejected(); + method public void onWrite(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.CancellationSignal); + field public static final int ERROR_CONCURRENT_REQUEST = 1; // 0x1 + field public static final int ERROR_UNKNOWN = 2; // 0x2 + } + } package android.view.inline { diff --git a/api/system-current.txt b/api/system-current.txt index 9cc7f08a655b..9da82ef10e0c 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5,6 +5,7 @@ package android { field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS"; field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO"; field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM"; + field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB"; field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS"; @@ -627,9 +628,12 @@ package android.app { public class KeyguardManager { method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence); + method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed(); method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback); + method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean); + method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean validateLockPasswordComplexity(boolean, @NonNull byte[], int); } public class Notification implements android.os.Parcelable { @@ -1776,6 +1780,7 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; + field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final String NETD_SERVICE = "netd"; @@ -1791,7 +1796,6 @@ package android.content { field public static final String STATUS_BAR_SERVICE = "statusbar"; field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; - field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry"; field public static final String TETHERING_SERVICE = "tethering"; field public static final String VR_SERVICE = "vrmanager"; @@ -1830,6 +1834,7 @@ package android.content { field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES"; field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION"; field public static final String ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION"; + field public static final String ACTION_PACKAGE_UNSUSPENDED_MANUALLY = "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY"; field public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED = "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED"; field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART"; @@ -1898,26 +1903,6 @@ package android.content { package android.content.integrity { - public final class AppInstallMetadata { - method @NonNull public String getAppCertificate(); - method @Nullable public String getInstallerCertificate(); - method @Nullable public String getInstallerName(); - method @NonNull public String getPackageName(); - method public int getVersionCode(); - method public boolean isPreInstalled(); - } - - public static final class AppInstallMetadata.Builder { - ctor public AppInstallMetadata.Builder(); - method @NonNull public android.content.integrity.AppInstallMetadata build(); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setAppCertificate(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerCertificate(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerName(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setIsPreInstalled(boolean); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setPackageName(@NonNull String); - method @NonNull public android.content.integrity.AppInstallMetadata.Builder setVersionCode(int); - } - public class AppIntegrityManager { method @NonNull public String getCurrentRuleSetProvider(); method @NonNull public String getCurrentRuleSetVersion(); @@ -1927,84 +1912,28 @@ package android.content.integrity { field public static final int STATUS_SUCCESS = 0; // 0x0 } - public abstract class AtomicFormula implements android.content.integrity.Formula { - ctor public AtomicFormula(int); - method public int getKey(); - field public static final int APP_CERTIFICATE = 1; // 0x1 - field public static final int EQ = 0; // 0x0 - field public static final int GE = 4; // 0x4 - field public static final int GT = 3; // 0x3 - field public static final int INSTALLER_CERTIFICATE = 3; // 0x3 - field public static final int INSTALLER_NAME = 2; // 0x2 - field public static final int LE = 2; // 0x2 - field public static final int LT = 1; // 0x1 - field public static final int PACKAGE_NAME = 0; // 0x0 - field public static final int PRE_INSTALLED = 5; // 0x5 - field public static final int VERSION_CODE = 4; // 0x4 - } - - public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.BooleanAtomicFormula(int, boolean); - method public int describeContents(); - method public int getTag(); - method public boolean getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.BooleanAtomicFormula> CREATOR; - } - - public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.IntAtomicFormula(int, int, int); - method public int describeContents(); - method public int getOperator(); - method public int getTag(); - method public int getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR; - } - - public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable { - ctor public AtomicFormula.StringAtomicFormula(int, @NonNull String, boolean); - method public int describeContents(); - method public boolean getIsHashedValue(); - method public int getTag(); - method @NonNull public String getValue(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.StringAtomicFormula> CREATOR; - } - - public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable { - ctor public CompoundFormula(int, @NonNull java.util.List<android.content.integrity.Formula>); - method public int describeContents(); - method public int getConnector(); - method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas(); - method public int getTag(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int AND = 0; // 0x0 - field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.CompoundFormula> CREATOR; - field public static final int NOT = 2; // 0x2 - field public static final int OR = 1; // 0x1 - } - - public interface Formula { - method public int getTag(); - method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata); - method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel); - method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int); - field public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3; // 0x3 - field public static final int COMPOUND_FORMULA_TAG = 0; // 0x0 - field public static final int INT_ATOMIC_FORMULA_TAG = 2; // 0x2 - field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1 + public abstract class IntegrityFormula { + method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(@NonNull String); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(boolean); + method @NonNull public android.content.integrity.IntegrityFormula equalTo(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThan(long); + method @NonNull public android.content.integrity.IntegrityFormula greaterThanOrEquals(long); + method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula); + field @NonNull public static final android.content.integrity.IntegrityFormula APP_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_CERTIFICATE; + field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PACKAGE_NAME; + field @NonNull public static final android.content.integrity.IntegrityFormula PRE_INSTALLED; + field @NonNull public static final android.content.integrity.IntegrityFormula VERSION_CODE; } public final class Rule implements android.os.Parcelable { - ctor public Rule(@NonNull android.content.integrity.Formula, int); + ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int); method public int describeContents(); method public int getEffect(); - method @NonNull public android.content.integrity.Formula getFormula(); + method @NonNull public android.content.integrity.IntegrityFormula getFormula(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR; field public static final int DENY = 0; // 0x0 @@ -2042,8 +1971,8 @@ package android.content.om { public class OverlayManager { method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle); method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle); - method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException; + method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException; } } @@ -2259,6 +2188,7 @@ package android.content.pm { method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String); method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo); method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean); + method public void setSystemAppState(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle); @@ -2339,6 +2269,10 @@ package android.content.pm { field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0 + field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1 + field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2 + field public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; // 0x3 } public abstract static class PackageManager.DexModuleRegisterCallback { @@ -2399,6 +2333,8 @@ package android.content.pm { public final class SuspendDialogInfo implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); + field public static final int BUTTON_ACTION_MORE_DETAILS = 0; // 0x0 + field public static final int BUTTON_ACTION_UNSUSPEND = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.SuspendDialogInfo> CREATOR; } @@ -2408,6 +2344,7 @@ package android.content.pm { method @NonNull public android.content.pm.SuspendDialogInfo.Builder setIcon(@DrawableRes int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@NonNull String); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@StringRes int); + method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonAction(int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(@StringRes int); method @NonNull public android.content.pm.SuspendDialogInfo.Builder setTitle(@StringRes int); } @@ -2582,7 +2519,7 @@ package android.hardware.display { method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String); method public android.util.Pair<float[],float[]> getCurve(); method public float getShortTermModelLowerLuxMultiplier(); - method public long getShortTermModelTimeout(); + method public long getShortTermModelTimeoutMillis(); method public float getShortTermModelUpperLuxMultiplier(); method public boolean shouldCollectColorSamples(); method public void writeToParcel(android.os.Parcel, int); @@ -2599,7 +2536,7 @@ package android.hardware.display { method public int getMaxCorrectionsByPackageName(); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float); - method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long); + method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean); } @@ -3004,7 +2941,7 @@ package android.hardware.location { public class ContextHubClient implements java.io.Closeable { method public void close(); method @NonNull public android.hardware.location.ContextHubInfo getAttachedHub(); - method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage); + method @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage); } public class ContextHubClientCallback { @@ -3053,24 +2990,24 @@ package android.hardware.location { } public final class ContextHubManager { - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); - method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter); - method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] getContextHubHandles(); - method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubInfo getContextHubInfo(int); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs(); - method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int); - method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] getContextHubHandles(); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubInfo getContextHubInfo(int); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs(); + method @Deprecated @Nullable @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo); method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler); - method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage); - method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int unloadNanoApp(int); - method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage); + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int unloadNanoApp(int); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback); field public static final int EVENT_HUB_RESET = 6; // 0x6 field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4 @@ -3864,12 +3801,15 @@ package android.location { public final class GnssMeasurementCorrections implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters(); + method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees(); + method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees(); method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters(); method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees(); method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees(); method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList(); method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek(); method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters(); + method public boolean hasEnvironmentBearing(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR; } @@ -3878,6 +3818,8 @@ package android.location { ctor public GnssMeasurementCorrections.Builder(); method @NonNull public android.location.GnssMeasurementCorrections build(); method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double); + method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float); + method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float); method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double); method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double); method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double); @@ -6136,6 +6078,19 @@ package android.net { method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network); } + public class EthernetManager { + method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback); + } + + public static interface EthernetManager.TetheredInterfaceCallback { + method public void onAvailable(@NonNull String); + method public void onUnavailable(); + } + + public static class EthernetManager.TetheredInterfaceRequest { + method public void release(); + } + public class InvalidPacketException extends java.lang.Exception { ctor public InvalidPacketException(int); field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb @@ -6565,6 +6520,7 @@ package android.net { field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 field public static final int TETHERING_INVALID = -1; // 0xffffffff field public static final int TETHERING_NCM = 4; // 0x4 field public static final int TETHERING_USB = 1; // 0x1 @@ -8891,7 +8847,6 @@ package android.os { method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getEuiccControllerService(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getIccPhoneBookServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getOpportunisticNetworkServiceRegisterer(); - method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPackageManagerServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getPhoneSubServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSmsServiceRegisterer(); method @NonNull public android.os.TelephonyServiceManager.ServiceRegisterer getSubscriptionServiceRegisterer(); @@ -9232,6 +9187,7 @@ package android.permission { public final class PermissionManager { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions(); + method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); @@ -9723,6 +9679,7 @@ package android.provider { public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final String APN_SET_ID = "apn_set_id"; + field @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask"; field public static final int CARRIER_EDITED = 4; // 0x4 field @NonNull public static final android.net.Uri DPC_URI; field public static final String EDITED_STATUS = "edited"; @@ -9731,6 +9688,11 @@ package android.provider { field public static final String MODEM_PERSIST = "modem_cognitive"; field public static final String MTU = "mtu"; field public static final int NO_APN_SET_ID = 0; // 0x0 + field public static final String PROFILE_ID = "profile_id"; + field public static final String SKIP_464XLAT = "skip_464xlat"; + field public static final int SKIP_464XLAT_DEFAULT = -1; // 0xffffffff + field public static final int SKIP_464XLAT_DISABLE = 0; // 0x0 + field public static final int SKIP_464XLAT_ENABLE = 1; // 0x1 field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time"; field public static final int UNEDITED = 0; // 0x0 field public static final int USER_DELETED = 2; // 0x2 @@ -10207,6 +10169,7 @@ package android.service.contentcapture { method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent); method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest); + method public void onDataShareRequest(@NonNull android.view.contentcapture.DataShareRequest, @NonNull android.service.contentcapture.DataShareCallback); method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId); method public void onDisconnected(); method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>); @@ -10215,6 +10178,16 @@ package android.service.contentcapture { field public static final String SERVICE_META_DATA = "android.content_capture"; } + public interface DataShareCallback { + method public void onAccept(@NonNull java.util.concurrent.Executor, @NonNull android.service.contentcapture.DataShareReadAdapter); + method public void onReject(); + } + + public interface DataShareReadAdapter { + method public void onError(int); + method public void onStart(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.CancellationSignal); + } + public final class SnapshotData implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.app.assist.AssistContent getAssistContent(); @@ -10931,7 +10904,14 @@ package android.telecom { } public final class PhoneAccount implements android.os.Parcelable { + field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80 + field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000 + field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200 field public static final int CAPABILITY_MULTI_USER = 32; // 0x20 + field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE"; + field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE"; + field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER"; + field public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK"; } public static class PhoneAccount.Builder { @@ -11017,10 +10997,20 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle); + field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED"; + field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED"; + field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1 + field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2 + field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0 field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT"; + field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE"; + field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE"; field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT"; field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"; + field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE"; field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL"; + field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE"; + field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE"; field public static final int TTY_MODE_FULL = 1; // 0x1 field public static final int TTY_MODE_HCO = 2; // 0x2 field public static final int TTY_MODE_OFF = 0; // 0x0 @@ -12270,6 +12260,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); @@ -13030,15 +13021,12 @@ package android.telephony.ims { } public class ImsManager { - method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; - field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); @@ -13406,8 +13394,8 @@ package android.telephony.ims { method public int describeContents(); method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags(); method @NonNull public android.net.Uri getContactUri(); - method @Nullable public android.net.Uri getServiceUri(int); - method public boolean isCapable(int); + method @Nullable public android.net.Uri getServiceUri(long); + method public boolean isCapable(long); method public boolean isCapable(@NonNull String); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 @@ -13429,6 +13417,7 @@ package android.telephony.ims { field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000 field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 @@ -13437,6 +13426,7 @@ package android.telephony.ims { field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 + field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000 field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR; @@ -13444,14 +13434,16 @@ package android.telephony.ims { public static class RcsContactUceCapability.Builder { ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri); - method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri); - method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long); method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String); method @NonNull public android.telephony.ims.RcsContactUceCapability build(); } public class RcsUceAdapter { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd field public static final int ERROR_FORBIDDEN = 6; // 0x6 @@ -13473,6 +13465,12 @@ package android.telephony.ims { field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3 } + public static class RcsUceAdapter.CapabilitiesCallback { + ctor public RcsUceAdapter.CapabilitiesCallback(); + method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>); + method public void onError(int); + } + } package android.telephony.ims.feature { @@ -13562,6 +13560,8 @@ package android.telephony.ims.feature { public class RcsFeature extends android.telephony.ims.feature.ImsFeature { ctor public RcsFeature(); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl(); + method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl(); method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities); method public void onFeatureReady(); method public void onFeatureRemoved(); @@ -13754,6 +13754,71 @@ package android.telephony.ims.stub { field public static final int INVALID_RESULT = -1; // 0xffffffff } + public class RcsCapabilityExchange { + ctor public RcsCapabilityExchange(); + method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException; + field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4 + field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2 + field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6 + field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3 + field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7 + field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9 + field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8 + field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb + field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa + field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0 + field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1 + } + + public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsPresenceExchangeImplBase(); + method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException; + method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException; + method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException; + method public final void onUnpublish() throws android.telephony.ims.ImsException; + method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int); + method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7 + field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9 + field public static final int RESPONSE_FORBIDDEN = 3; // 0x3 + field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2 + field public static final int RESPONSE_NOT_FOUND = 4; // 0x4 + field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1 + field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7 + field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8 + field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + } + + public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsSipOptionsImplBase(); + method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int); + method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int); + method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5 + field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4 + field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_NOT_FOUND = 3; // 0x3 + field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1 + } + } package android.telephony.mbms { diff --git a/api/test-current.txt b/api/test-current.txt index 76af40318fb8..837706b36442 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -77,6 +77,8 @@ package android.app { method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle); field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7 + field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1 + field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6 field public static final int PROCESS_CAPABILITY_FOREGROUND_CAMERA = 2; // 0x2 field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1 field public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 4; // 0x4 @@ -769,12 +771,12 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String STATUS_BAR_SERVICE = "statusbar"; - field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TEST_NETWORK_SERVICE = "test_network"; } @@ -1089,7 +1091,7 @@ package android.hardware.display { method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String); method public android.util.Pair<float[],float[]> getCurve(); method public float getShortTermModelLowerLuxMultiplier(); - method public long getShortTermModelTimeout(); + method public long getShortTermModelTimeoutMillis(); method public float getShortTermModelUpperLuxMultiplier(); method public boolean shouldCollectColorSamples(); method public void writeToParcel(android.os.Parcel, int); @@ -1106,7 +1108,7 @@ package android.hardware.display { method public int getMaxCorrectionsByPackageName(); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float); - method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long); + method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean); } @@ -1610,6 +1612,19 @@ package android.net { field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; } + public class EthernetManager { + method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback); + } + + public static interface EthernetManager.TetheredInterfaceCallback { + method public void onAvailable(@NonNull String); + method public void onUnavailable(); + } + + public static class EthernetManager.TetheredInterfaceRequest { + method public void release(); + } + public final class IpPrefix implements android.os.Parcelable { ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); ctor public IpPrefix(@NonNull String); @@ -1758,6 +1773,7 @@ package android.net { field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 field public static final int TETHERING_INVALID = -1; // 0xffffffff field public static final int TETHERING_NCM = 4; // 0x4 field public static final int TETHERING_USB = 1; // 0x1 @@ -3791,15 +3807,12 @@ package android.telephony.ims { } public class ImsManager { - method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; - field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); @@ -4159,8 +4172,60 @@ package android.telephony.ims { method public void onProvisioningStringChanged(int, @NonNull String); } + public final class RcsContactUceCapability implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags(); + method @NonNull public android.net.Uri getContactUri(); + method @Nullable public android.net.Uri getServiceUri(long); + method public boolean isCapable(long); + method public boolean isCapable(@NonNull String); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 + field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000 + field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000 + field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2 + field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4 + field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1 + field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000 + field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8 + field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40 + field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80 + field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20 + field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10 + field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000 + field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000 + field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000 + field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000 + field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 + field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 + field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000 + field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 + field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 + field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 + field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000 + field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000 + field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 + field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 + field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 + field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000 + field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 + field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR; + } + + public static class RcsContactUceCapability.Builder { + ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String); + method @NonNull public android.telephony.ims.RcsContactUceCapability build(); + } + public class RcsUceAdapter { + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getUcePublishState() throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException; + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd field public static final int ERROR_FORBIDDEN = 6; // 0x6 @@ -4182,6 +4247,12 @@ package android.telephony.ims { field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3 } + public static class RcsUceAdapter.CapabilitiesCallback { + ctor public RcsUceAdapter.CapabilitiesCallback(); + method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>); + method public void onError(int); + } + } package android.telephony.ims.feature { @@ -4271,6 +4342,8 @@ package android.telephony.ims.feature { public class RcsFeature extends android.telephony.ims.feature.ImsFeature { ctor public RcsFeature(); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl(); + method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl(); method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities); method public void onFeatureReady(); method public void onFeatureRemoved(); @@ -4463,6 +4536,71 @@ package android.telephony.ims.stub { field public static final int INVALID_RESULT = -1; // 0xffffffff } + public class RcsCapabilityExchange { + ctor public RcsCapabilityExchange(); + method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException; + field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4 + field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2 + field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6 + field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3 + field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7 + field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9 + field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8 + field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb + field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa + field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0 + field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1 + } + + public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsPresenceExchangeImplBase(); + method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException; + method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException; + method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException; + method public final void onUnpublish() throws android.telephony.ims.ImsException; + method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int); + method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7 + field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9 + field public static final int RESPONSE_FORBIDDEN = 3; // 0x3 + field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2 + field public static final int RESPONSE_NOT_FOUND = 4; // 0x4 + field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1 + field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7 + field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8 + field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + } + + public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsSipOptionsImplBase(); + method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int); + method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int); + method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5 + field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4 + field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_NOT_FOUND = 3; // 0x3 + field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1 + } + } package android.telephony.mbms { diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 080b1af35059..ac24a553b555 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -50,7 +50,6 @@ cc_defaults { srcs: [ ":statsd_aidl", - ":ICarStatsService.aidl", "src/active_config_list.proto", "src/anomaly/AlarmMonitor.cpp", "src/anomaly/AlarmTracker.cpp", @@ -65,7 +64,6 @@ cc_defaults { "src/config/ConfigKey.cpp", "src/config/ConfigListener.cpp", "src/config/ConfigManager.cpp", - "src/external/CarStatsPuller.cpp", "src/external/GpuStatsPuller.cpp", "src/external/Perfetto.cpp", "src/external/PowerStatsPuller.cpp", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 795062675f3f..177b699f5e7c 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -151,8 +151,8 @@ message Atom { HardwareFailed hardware_failed = 72; PhysicalDropDetected physical_drop_detected = 73; ChargeCyclesReported charge_cycles_reported = 74; - MobileConnectionStateChanged mobile_connection_state_changed = 75; - MobileRadioTechnologyChanged mobile_radio_technology_changed = 76; + MobileConnectionStateChanged mobile_connection_state_changed = 75 [(module) = "telephony"]; + MobileRadioTechnologyChanged mobile_radio_technology_changed = 76 [(module) = "telephony"]; UsbDeviceAttached usb_device_attached = 77; AppCrashOccurred app_crash_occurred = 78; ANROccurred anr_occurred = 79; @@ -343,6 +343,10 @@ message Atom { NotificationChannelModified notification_panel_modified = 246; IntegrityCheckResultReported integrity_check_result_reported = 247; IntegrityRulesPushed integrity_rules_pushed = 248; + CellBroadcastMessageReported cb_message_reported = + 249 [(module) = "cellbroadcast"]; + CellBroadcastMessageError cb_message_error = + 250 [(module) = "cellbroadcast"]; } // Pulled events will start at field 10000. @@ -8112,3 +8116,55 @@ message IntegrityRulesPushed { // identify the rules. optional string rule_version = 3; } + +/** + * Logs when a cell broadcast message is received on the device. + * + * Logged from CellBroadcastService module: + * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + */ +message CellBroadcastMessageReported { + // The type of Cell Broadcast message + enum CbType { + UNKNOWN_TYPE = 0; + GSM = 1; + CDMA = 2; + CDMA_SPC = 3; + } + + // GSM, CDMA, CDMA-SCP + optional CbType type = 1; +} + +/** + * Logs when an error occurs while handling a cell broadcast message; + * + * Logged from CellBroadcastService module: + * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + */ +message CellBroadcastMessageError { + // The type of error raised when trying to handle a cell broadcast message + enum ErrorType { + UNKNOWN_TYPE = 0; + CDMA_DECODING_ERROR = 1; + CDMA_SCP_EMPTY = 2; + CDMA_SCP_HANDLING_ERROR = 3; + GSM_INVALID_HEADER_LENGTH = 4; + GSM_UNSUPPORTED_HEADER_MESSAGE_TYPE = 5; + GSM_UNSUPPORTED_HEADER_DATA_CODING_SCHEME = 6; + GSM_INVALID_PDU = 7; + GSM_INVALID_GEO_FENCING_DATA = 8; + GSM_UMTS_INVALID_WAC = 9; + FAILED_TO_INSERT_TO_DB = 10; + UNEXPECTED_GEOMETRY_FROM_FWK = 11; + UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12; + UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13; + UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14; + } + + // What kind of error occurred + optional ErrorType type = 1; + + // Exception message (or log message) associated with the error (max 1000 chars) + optional string exception_message = 2; +} diff --git a/cmds/statsd/src/external/CarStatsPuller.cpp b/cmds/statsd/src/external/CarStatsPuller.cpp deleted file mode 100644 index 70c0456b5eb4..000000000000 --- a/cmds/statsd/src/external/CarStatsPuller.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define DEBUG false -#include "Log.h" - -#include <binder/IServiceManager.h> -#include <com/android/internal/car/ICarStatsService.h> - -#include "CarStatsPuller.h" -#include "logd/LogEvent.h" -#include "stats_log_util.h" - -using android::binder::Status; -using com::android::internal::car::ICarStatsService; - -namespace android { -namespace os { -namespace statsd { - -static std::mutex gCarStatsMutex; -static sp<ICarStatsService> gCarStats = nullptr; - -class CarStatsDeathRecipient : public android::IBinder::DeathRecipient { - public: - CarStatsDeathRecipient() = default; - ~CarStatsDeathRecipient() override = default; - - // android::IBinder::DeathRecipient override: - void binderDied(const android::wp<android::IBinder>& /* who */) override { - ALOGE("Car service has died"); - std::lock_guard<std::mutex> lock(gCarStatsMutex); - if (gCarStats) { - sp<IBinder> binder = IInterface::asBinder(gCarStats); - binder->unlinkToDeath(this); - gCarStats = nullptr; - } - } -}; - -static sp<CarStatsDeathRecipient> gDeathRecipient = new CarStatsDeathRecipient(); - -static sp<ICarStatsService> getCarService() { - std::lock_guard<std::mutex> lock(gCarStatsMutex); - if (!gCarStats) { - const sp<IBinder> binder = defaultServiceManager()->checkService(String16("car_stats")); - if (!binder) { - ALOGW("Car service is unavailable"); - return nullptr; - } - gCarStats = interface_cast<ICarStatsService>(binder); - binder->linkToDeath(gDeathRecipient); - } - return gCarStats; -} - -CarStatsPuller::CarStatsPuller(const int tagId) : StatsPuller(tagId) { -} - -bool CarStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) { - const sp<ICarStatsService> carService = getCarService(); - if (!carService) { - return false; - } - - vector<StatsLogEventWrapper> returned_value; - Status status = carService->pullData(mTagId, &returned_value); - if (!status.isOk()) { - ALOGW("CarStatsPuller::pull failed for %d", mTagId); - return false; - } - - data->clear(); - for (const StatsLogEventWrapper& it : returned_value) { - LogEvent::createLogEvents(it, *data); - } - VLOG("CarStatsPuller::pull succeeded for %d", mTagId); - return true; -} - -} // namespace statsd -} // namespace os -} // namespace android diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h index ab2c1954e2a0..095782a49f9b 100644 --- a/cmds/statsd/src/external/Perfetto.h +++ b/cmds/statsd/src/external/Perfetto.h @@ -16,10 +16,6 @@ #pragma once -#include <android/os/StatsLogEventWrapper.h> - -using android::os::StatsLogEventWrapper; - namespace android { namespace os { namespace statsd { diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp index e5a83a27bfcf..6257771b5b0d 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.cpp +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -36,8 +36,9 @@ namespace os { namespace statsd { StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback, - int64_t timeoutNs) - : StatsPuller(tagId), mCallback(callback), mTimeoutNs(timeoutNs) { + const int64_t coolDownNs, int64_t timeoutNs, + const vector<int> additiveFields) + : StatsPuller(tagId, coolDownNs, timeoutNs, additiveFields), mCallback(callback) { VLOG("StatsCallbackPuller created for tag %d", tagId); } @@ -86,7 +87,7 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { { unique_lock<mutex> unique_lk(*cv_mutex); // Wait until the pull finishes, or until the pull timeout. - cv->wait_for(unique_lk, chrono::nanoseconds(mTimeoutNs), + cv->wait_for(unique_lk, chrono::nanoseconds(mPullTimeoutNs), [pullFinish] { return *pullFinish; }); if (!*pullFinish) { // Note: The parent stats puller will also note that there was a timeout and that the diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h index d943f9d189c5..ac88524a72ee 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.h +++ b/cmds/statsd/src/external/StatsCallbackPuller.h @@ -28,12 +28,12 @@ namespace statsd { class StatsCallbackPuller : public StatsPuller { public: explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback, - int64_t timeoutNs); + const int64_t coolDownNs, const int64_t timeoutNs, + const std::vector<int> additiveFields); private: bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override; const sp<IPullAtomCallback> mCallback; - const int64_t mTimeoutNs; FRIEND_TEST(StatsCallbackPullerTest, PullFail); FRIEND_TEST(StatsCallbackPullerTest, PullSuccess); diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp index 883bd28a4d13..5192ddf301e1 100644 --- a/cmds/statsd/src/external/StatsPuller.cpp +++ b/cmds/statsd/src/external/StatsPuller.cpp @@ -32,17 +32,20 @@ using std::lock_guard; sp<UidMap> StatsPuller::mUidMap = nullptr; void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; } -StatsPuller::StatsPuller(const int tagId) - : mTagId(tagId), mLastPullTimeNs(0) { +StatsPuller::StatsPuller(const int tagId, const int64_t coolDownNs, const int64_t pullTimeoutNs, + const std::vector<int> additiveFields) + : mTagId(tagId), + mPullTimeoutNs(pullTimeoutNs), + mCoolDownNs(coolDownNs), + mAdditiveFields(additiveFields), + mLastPullTimeNs(0) { } bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { lock_guard<std::mutex> lock(mLock); int64_t elapsedTimeNs = getElapsedRealtimeNs(); StatsdStats::getInstance().notePull(mTagId); - const bool shouldUseCache = - elapsedTimeNs - mLastPullTimeNs < - StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).coolDownNs; + const bool shouldUseCache = elapsedTimeNs - mLastPullTimeNs < mCoolDownNs; if (shouldUseCache) { if (mHasGoodData) { (*data) = mCachedData; @@ -64,9 +67,7 @@ bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { } const int64_t pullDurationNs = getElapsedRealtimeNs() - elapsedTimeNs; StatsdStats::getInstance().notePullTime(mTagId, pullDurationNs); - const bool pullTimeOut = - pullDurationNs > - StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).pullTimeoutNs; + const bool pullTimeOut = pullDurationNs > mPullTimeoutNs; if (pullTimeOut) { // Something went wrong. Discard the data. clearCacheLocked(); @@ -78,7 +79,7 @@ bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) { } if (mCachedData.size() > 0) { - mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId); + mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId, mAdditiveFields); } (*data) = mCachedData; @@ -102,8 +103,7 @@ int StatsPuller::clearCacheLocked() { } int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) { - if (timestampNs - mLastPullTimeNs > - StatsPullerManager::kAllPullAtomInfo.at({.atomTag = mTagId}).coolDownNs) { + if (timestampNs - mLastPullTimeNs > mCoolDownNs) { return clearCache(); } else { return 0; diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index c83c4f8536ae..9c2169565094 100644 --- a/cmds/statsd/src/external/StatsPuller.h +++ b/cmds/statsd/src/external/StatsPuller.h @@ -32,7 +32,10 @@ namespace statsd { class StatsPuller : public virtual RefBase { public: - explicit StatsPuller(const int tagId); + explicit StatsPuller(const int tagId, + const int64_t coolDownNs = NS_PER_SEC, + const int64_t pullTimeoutNs = StatsdStats::kPullMaxDelayNs, + const std::vector<int> additiveFields = std::vector<int>()); virtual ~StatsPuller() {} @@ -60,6 +63,12 @@ public: protected: const int mTagId; + // Max time allowed to pull this atom. + // We cannot reliably kill a pull thread. So we don't terminate the puller. + // The data is discarded if the pull takes longer than this and mHasGoodData + // marked as false. + const int64_t mPullTimeoutNs = StatsdStats::kPullMaxDelayNs; + private: mutable std::mutex mLock; @@ -68,6 +77,17 @@ private: bool mHasGoodData = false; + // Minimum time before this puller does actual pull again. + // Pullers can cause significant impact to system health and battery. + // So that we don't pull too frequently. + // If a pull request comes before cooldown, a cached version from previous pull + // will be returned. + const int64_t mCoolDownNs = 1 * NS_PER_SEC; + + // The field numbers of the fields that need to be summed when merging + // isolated uid with host uid. + const std::vector<int> mAdditiveFields; + int64_t mLastPullTimeNs; // Cache of data from last pull. If next request comes before cool down finishes, diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 8d67b5c169f5..7708e300929e 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -32,7 +32,6 @@ #include "../logd/LogEvent.h" #include "../stats_log_util.h" #include "../statscompanion_util.h" -#include "CarStatsPuller.h" #include "GpuStatsPuller.h" #include "PowerStatsPuller.h" #include "ResourceHealthManagerPuller.h" @@ -55,54 +54,47 @@ namespace statsd { // Values smaller than this may require to update the alarm. const int64_t NO_ALARM_UPDATE = INT64_MAX; -std::map<PullerKey, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { +StatsPullerManager::StatsPullerManager() + : kAllPullAtomInfo({ + // subsystem_sleep_state + {{.atomTag = android::util::SUBSYSTEM_SLEEP_STATE}, new SubsystemSleepStatePuller()}, - // subsystem_sleep_state - {{.atomTag = android::util::SUBSYSTEM_SLEEP_STATE}, - {.puller = new SubsystemSleepStatePuller()}}, + // on_device_power_measurement + {{.atomTag = android::util::ON_DEVICE_POWER_MEASUREMENT}, new PowerStatsPuller()}, - // on_device_power_measurement - {{.atomTag = android::util::ON_DEVICE_POWER_MEASUREMENT}, - {.puller = new PowerStatsPuller()}}, + // remaining_battery_capacity + {{.atomTag = android::util::REMAINING_BATTERY_CAPACITY}, + new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}, - // remaining_battery_capacity - {{.atomTag = android::util::REMAINING_BATTERY_CAPACITY}, - {.puller = new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}}, + // full_battery_capacity + {{.atomTag = android::util::FULL_BATTERY_CAPACITY}, + new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}, - // full_battery_capacity - {{.atomTag = android::util::FULL_BATTERY_CAPACITY}, - {.puller = new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, + // battery_voltage + {{.atomTag = android::util::BATTERY_VOLTAGE}, + new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}, - // battery_voltage - {{.atomTag = android::util::BATTERY_VOLTAGE}, - {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}}, + // battery_level + {{.atomTag = android::util::BATTERY_LEVEL}, + new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}, - // battery_level - {{.atomTag = android::util::BATTERY_LEVEL}, - {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}}, + // battery_cycle_count + {{.atomTag = android::util::BATTERY_CYCLE_COUNT}, + new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}, - // battery_cycle_count - {{.atomTag = android::util::BATTERY_CYCLE_COUNT}, - {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}}, + // TrainInfo. + {{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()}, - // TrainInfo. - {{.atomTag = android::util::TRAIN_INFO}, {.puller = new TrainInfoPuller()}}, + // GpuStatsGlobalInfo + {{.atomTag = android::util::GPU_STATS_GLOBAL_INFO}, + new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}, - // GpuStatsGlobalInfo - {{.atomTag = android::util::GPU_STATS_GLOBAL_INFO}, - {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}}, + // GpuStatsAppInfo + {{.atomTag = android::util::GPU_STATS_APP_INFO}, + new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}, - // GpuStatsAppInfo - {{.atomTag = android::util::GPU_STATS_APP_INFO}, - {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}}, - - // VmsClientStats - {{.atomTag = android::util::VMS_CLIENT_STATS}, - {.additiveFields = {5, 6, 7, 8, 9, 10}, - .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}}, -}; - -StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { + }), + mNextPullTimeNs(NO_ALARM_UPDATE) { } bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) { @@ -114,7 +106,7 @@ bool StatsPullerManager::PullLocked(int tagId, vector<shared_ptr<LogEvent>>* dat VLOG("Initiating pulling %d", tagId); if (kAllPullAtomInfo.find({.atomTag = tagId}) != kAllPullAtomInfo.end()) { - bool ret = kAllPullAtomInfo.find({.atomTag = tagId})->second.puller->Pull(data); + bool ret = kAllPullAtomInfo.find({.atomTag = tagId})->second->Pull(data); VLOG("pulled %d items", (int)data->size()); if (!ret) { StatsdStats::getInstance().notePullFailed(tagId); @@ -153,7 +145,7 @@ void StatsPullerManager::SetStatsCompanionService( sp<IStatsCompanionService> tmpForLock = mStatsCompanionService; mStatsCompanionService = statsCompanionService; for (const auto& pulledAtom : kAllPullAtomInfo) { - pulledAtom.second.puller->SetStatsCompanionService(statsCompanionService); + pulledAtom.second->SetStatsCompanionService(statsCompanionService); } if (mStatsCompanionService != nullptr) { updateAlarmLocked(); @@ -285,7 +277,7 @@ void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) { int StatsPullerManager::ForceClearPullerCache() { int totalCleared = 0; for (const auto& pulledAtom : kAllPullAtomInfo) { - totalCleared += pulledAtom.second.puller->ForceClearCache(); + totalCleared += pulledAtom.second->ForceClearCache(); } return totalCleared; } @@ -293,7 +285,7 @@ int StatsPullerManager::ForceClearPullerCache() { int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) { int totalCleared = 0; for (const auto& pulledAtom : kAllPullAtomInfo) { - totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampNs); + totalCleared += pulledAtom.second->ClearCacheIfNecessary(timestampNs); } return totalCleared; } @@ -306,12 +298,8 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag); // TODO: linkToDeath with the callback so that we can remove it and delete the puller. StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); - kAllPullAtomInfo[{.atomTag = atomTag}] = { - .additiveFields = additiveFields, - .coolDownNs = coolDownNs, - .puller = new StatsCallbackPuller(atomTag, callback, timeoutNs), - .pullTimeoutNs = timeoutNs, - }; + kAllPullAtomInfo[{.atomTag = atomTag}] = + new StatsCallbackPuller(atomTag, callback, coolDownNs, timeoutNs, additiveFields); } void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag) { diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h index 4b6ab57b3bbe..f5d6057c2aec 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -36,24 +36,6 @@ namespace android { namespace os { namespace statsd { -typedef struct { - // The field numbers of the fields that need to be summed when merging - // isolated uid with host uid. - std::vector<int> additiveFields; - // Minimum time before this puller does actual pull again. - // Pullers can cause significant impact to system health and battery. - // So that we don't pull too frequently. - // If a pull request comes before cooldown, a cached version from previous pull - // will be returned. - int64_t coolDownNs = 1 * NS_PER_SEC; - // The actual puller - sp<StatsPuller> puller; - // Max time allowed to pull this atom. - // We cannot reliably kill a pull thread. So we don't terminate the puller. - // The data is discarded if the pull takes longer than this and mHasGoodData - // marked as false. - int64_t pullTimeoutNs = StatsdStats::kPullMaxDelayNs; -} PullAtomInfo; typedef struct PullerKey { // The uid of the process that registers this puller. @@ -121,7 +103,7 @@ public: void UnregisterPullAtomCallback(const int uid, const int32_t atomTag); - static std::map<PullerKey, PullAtomInfo> kAllPullAtomInfo; + std::map<const PullerKey, sp<StatsPuller>> kAllPullAtomInfo; private: sp<IStatsCompanionService> mStatsCompanionService = nullptr; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index 031c43740d9d..aee725698c30 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -17,7 +17,6 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" -#include "StatsPullerManager.h" #include "atoms_info.h" #include "puller_util.h" @@ -25,12 +24,7 @@ namespace android { namespace os { namespace statsd { -using std::list; -using std::map; -using std::set; -using std::shared_ptr; -using std::sort; -using std::vector; +using namespace std; /** * Process all data and merge isolated with host if necessary. @@ -54,12 +48,7 @@ using std::vector; * All atoms should be of the same tagId. All fields should be present. */ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap, - int tagId) { - if (StatsPullerManager::kAllPullAtomInfo.find({.atomTag = tagId}) == - StatsPullerManager::kAllPullAtomInfo.end()) { - VLOG("Unknown pull atom id %d", tagId); - return; - } + int tagId, const vector<int>& additiveFieldsVec) { if ((android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) == android::util::AtomsInfo::kAtomsWithAttributionChain.end()) && (android::util::AtomsInfo::kAtomsWithUidField.find(tagId) == @@ -120,8 +109,6 @@ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const }); vector<shared_ptr<LogEvent>> mergedData; - const vector<int>& additiveFieldsVec = - StatsPullerManager::kAllPullAtomInfo.find({.atomTag = tagId})->second.additiveFields; const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end()); bool needMerge = true; diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h index f703e6c589c1..afcf68ca10ad 100644 --- a/cmds/statsd/src/external/puller_util.h +++ b/cmds/statsd/src/external/puller_util.h @@ -26,7 +26,8 @@ namespace os { namespace statsd { void mapAndMergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data, - const sp<UidMap>& uidMap, int tagId); + const sp<UidMap>& uidMap, int tagId, + const vector<int>& additiveFieldsVec); } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 36f4623c4dcb..3827b9e21b70 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -71,70 +71,6 @@ LogEvent::LogEvent(const LogEvent& event) { mValues = event.mValues; } -LogEvent::LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex) { - mTagId = statsLogEventWrapper.getTagId(); - mLogdTimestampNs = statsLogEventWrapper.getWallClockTimeNs(); - mElapsedTimestampNs = statsLogEventWrapper.getElapsedRealTimeNs(); - mLogUid = 0; - int workChainPosOffset = 0; - if (workChainIndex != -1) { - const WorkChain& wc = statsLogEventWrapper.getWorkChains()[workChainIndex]; - // chains are at field 1, level 2 - int depth = 2; - for (int i = 0; i < (int)wc.uids.size(); i++) { - int pos[] = {1, i + 1, 1}; - mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.uids[i]))); - pos[2]++; - mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(wc.tags[i]))); - mValues.back().mField.decorateLastPos(2); - } - mValues.back().mField.decorateLastPos(1); - workChainPosOffset = 1; - } - for (int i = 0; i < (int)statsLogEventWrapper.getElements().size(); i++) { - Field field(statsLogEventWrapper.getTagId(), getSimpleField(i + 1 + workChainPosOffset)); - switch (statsLogEventWrapper.getElements()[i].type) { - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::INT: - mValues.push_back( - FieldValue(field, Value(statsLogEventWrapper.getElements()[i].int_value))); - break; - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::LONG: - mValues.push_back( - FieldValue(field, Value(statsLogEventWrapper.getElements()[i].long_value))); - break; - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::FLOAT: - mValues.push_back(FieldValue( - field, Value(statsLogEventWrapper.getElements()[i].float_value))); - break; - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::DOUBLE: - mValues.push_back(FieldValue( - field, Value(statsLogEventWrapper.getElements()[i].double_value))); - break; - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::STRING: - mValues.push_back( - FieldValue(field, Value(statsLogEventWrapper.getElements()[i].str_value))); - break; - case android::os::StatsLogValue::STATS_LOG_VALUE_TYPE::STORAGE: - mValues.push_back(FieldValue( - field, Value(statsLogEventWrapper.getElements()[i].storage_value))); - break; - default: - break; - } - } -} - -void LogEvent::createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper, - std::vector<std::shared_ptr<LogEvent>>& logEvents) { - if (statsLogEventWrapper.getWorkChains().size() == 0) { - logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, -1)); - } else { - for (size_t i = 0; i < statsLogEventWrapper.getWorkChains().size(); i++) { - logEvents.push_back(std::make_shared<LogEvent>(statsLogEventWrapper, i)); - } - } -} - LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) { mLogdTimestampNs = wallClockTimestampNs; mElapsedTimestampNs = elapsedTimestampNs; diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 596d623debe5..0f33c56be42a 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -19,7 +19,6 @@ #include "FieldValue.h" #include <android/frameworks/stats/1.0/types.h> -#include <android/os/StatsLogEventWrapper.h> #include <android/util/ProtoOutputStream.h> #include <log/log_read.h> #include <private/android_logger.h> @@ -80,17 +79,6 @@ public: explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema); /** - * Creates LogEvent from StatsLogEventWrapper. - */ - static void createLogEvents(const StatsLogEventWrapper& statsLogEventWrapper, - std::vector<std::shared_ptr<LogEvent>>& logEvents); - - /** - * Construct one LogEvent from a StatsLogEventWrapper with the i-th work chain. -1 if no chain. - */ - explicit LogEvent(const StatsLogEventWrapper& statsLogEventWrapper, int workChainIndex); - - /** * Constructs a LogEvent with synthetic data for testing. Must call init() before reading. */ explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs); diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 9f50701d5e9e..1cf9fb681d61 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -665,168 +665,6 @@ TEST(LogEventTest, TestKeyValuePairsEvent) { EXPECT_EQ(1.1f, item16.mValue.float_value); } -TEST(LogEventTest, TestStatsLogEventWrapperNoChain) { - Parcel parcel; - // tag id - parcel.writeInt32(1); - // elapsed realtime - parcel.writeInt64(1111L); - // wallclock time - parcel.writeInt64(2222L); - // no chain - parcel.writeInt32(0); - // 2 data - parcel.writeInt32(2); - // int 6 - parcel.writeInt32(1); - parcel.writeInt32(6); - // long 10 - parcel.writeInt32(2); - parcel.writeInt64(10); - parcel.setDataPosition(0); - - StatsLogEventWrapper statsLogEventWrapper; - EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel)); - EXPECT_EQ(1, statsLogEventWrapper.getTagId()); - EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs()); - EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs()); - EXPECT_EQ(0, statsLogEventWrapper.getWorkChains().size()); - EXPECT_EQ(2, statsLogEventWrapper.getElements().size()); - EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value); - EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value); - LogEvent event(statsLogEventWrapper, -1); - EXPECT_EQ(1, event.GetTagId()); - EXPECT_EQ(1111L, event.GetElapsedTimestampNs()); - EXPECT_EQ(2222L, event.GetLogdTimestampNs()); - EXPECT_EQ(2, event.size()); - EXPECT_EQ(6, event.getValues()[0].mValue.int_value); - EXPECT_EQ(10, event.getValues()[1].mValue.long_value); -} - -TEST(LogEventTest, TestStatsLogEventWrapperWithChain) { - Parcel parcel; - // tag id - parcel.writeInt32(1); - // elapsed realtime - parcel.writeInt64(1111L); - // wallclock time - parcel.writeInt64(2222L); - // 3 chains - parcel.writeInt32(3); - // chain1, 2 nodes (1, "tag1") (2, "tag2") - parcel.writeInt32(2); - parcel.writeInt32(1); - parcel.writeString16(String16("tag1")); - parcel.writeInt32(2); - parcel.writeString16(String16("tag2")); - // chain2, 1 node (3, "tag3") - parcel.writeInt32(1); - parcel.writeInt32(3); - parcel.writeString16(String16("tag3")); - // chain3, 2 nodes (4, "") (5, "") - parcel.writeInt32(2); - parcel.writeInt32(4); - parcel.writeString16(String16("")); - parcel.writeInt32(5); - parcel.writeString16(String16("")); - // 2 data - parcel.writeInt32(2); - // int 6 - parcel.writeInt32(1); - parcel.writeInt32(6); - // long 10 - parcel.writeInt32(2); - parcel.writeInt64(10); - parcel.setDataPosition(0); - - StatsLogEventWrapper statsLogEventWrapper; - EXPECT_EQ(NO_ERROR, statsLogEventWrapper.readFromParcel(&parcel)); - EXPECT_EQ(1, statsLogEventWrapper.getTagId()); - EXPECT_EQ(1111L, statsLogEventWrapper.getElapsedRealTimeNs()); - EXPECT_EQ(2222L, statsLogEventWrapper.getWallClockTimeNs()); - EXPECT_EQ(3, statsLogEventWrapper.getWorkChains().size()); - EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids.size()); - EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[0].uids[0]); - EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].uids[1]); - EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[0].tags.size()); - EXPECT_EQ("tag1", statsLogEventWrapper.getWorkChains()[0].tags[0]); - EXPECT_EQ("tag2", statsLogEventWrapper.getWorkChains()[0].tags[1]); - EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].uids.size()); - EXPECT_EQ(3, statsLogEventWrapper.getWorkChains()[1].uids[0]); - EXPECT_EQ(1, statsLogEventWrapper.getWorkChains()[1].tags.size()); - EXPECT_EQ("tag3", statsLogEventWrapper.getWorkChains()[1].tags[0]); - EXPECT_EQ(2, statsLogEventWrapper.getElements().size()); - EXPECT_EQ(6, statsLogEventWrapper.getElements()[0].int_value); - EXPECT_EQ(10L, statsLogEventWrapper.getElements()[1].long_value); - EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].uids.size()); - EXPECT_EQ(4, statsLogEventWrapper.getWorkChains()[2].uids[0]); - EXPECT_EQ(5, statsLogEventWrapper.getWorkChains()[2].uids[1]); - EXPECT_EQ(2, statsLogEventWrapper.getWorkChains()[2].tags.size()); - EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[0]); - EXPECT_EQ("", statsLogEventWrapper.getWorkChains()[2].tags[1]); - - LogEvent event(statsLogEventWrapper, -1); - EXPECT_EQ(1, event.GetTagId()); - EXPECT_EQ(1111L, event.GetElapsedTimestampNs()); - EXPECT_EQ(2222L, event.GetLogdTimestampNs()); - EXPECT_EQ(2, event.size()); - EXPECT_EQ(6, event.getValues()[0].mValue.int_value); - EXPECT_EQ(10, event.getValues()[1].mValue.long_value); - - LogEvent event1(statsLogEventWrapper, 0); - - EXPECT_EQ(1, event1.GetTagId()); - EXPECT_EQ(1111L, event1.GetElapsedTimestampNs()); - EXPECT_EQ(2222L, event1.GetLogdTimestampNs()); - EXPECT_EQ(6, event1.size()); - EXPECT_EQ(1, event1.getValues()[0].mValue.int_value); - EXPECT_EQ(0x2010101, event1.getValues()[0].mField.getField()); - EXPECT_EQ("tag1", event1.getValues()[1].mValue.str_value); - EXPECT_EQ(0x2010182, event1.getValues()[1].mField.getField()); - EXPECT_EQ(2, event1.getValues()[2].mValue.int_value); - EXPECT_EQ(0x2010201, event1.getValues()[2].mField.getField()); - EXPECT_EQ("tag2", event1.getValues()[3].mValue.str_value); - EXPECT_EQ(0x2018282, event1.getValues()[3].mField.getField()); - EXPECT_EQ(6, event1.getValues()[4].mValue.int_value); - EXPECT_EQ(0x20000, event1.getValues()[4].mField.getField()); - EXPECT_EQ(10, event1.getValues()[5].mValue.long_value); - EXPECT_EQ(0x30000, event1.getValues()[5].mField.getField()); - - LogEvent event2(statsLogEventWrapper, 1); - - EXPECT_EQ(1, event2.GetTagId()); - EXPECT_EQ(1111L, event2.GetElapsedTimestampNs()); - EXPECT_EQ(2222L, event2.GetLogdTimestampNs()); - EXPECT_EQ(4, event2.size()); - EXPECT_EQ(3, event2.getValues()[0].mValue.int_value); - EXPECT_EQ(0x2010101, event2.getValues()[0].mField.getField()); - EXPECT_EQ("tag3", event2.getValues()[1].mValue.str_value); - EXPECT_EQ(0x2018182, event2.getValues()[1].mField.getField()); - EXPECT_EQ(6, event2.getValues()[2].mValue.int_value); - EXPECT_EQ(0x20000, event2.getValues()[2].mField.getField()); - EXPECT_EQ(10, event2.getValues()[3].mValue.long_value); - EXPECT_EQ(0x30000, event2.getValues()[3].mField.getField()); - - LogEvent event3(statsLogEventWrapper, 2); - - EXPECT_EQ(1, event3.GetTagId()); - EXPECT_EQ(1111L, event3.GetElapsedTimestampNs()); - EXPECT_EQ(2222L, event3.GetLogdTimestampNs()); - EXPECT_EQ(6, event3.size()); - EXPECT_EQ(4, event3.getValues()[0].mValue.int_value); - EXPECT_EQ(0x2010101, event3.getValues()[0].mField.getField()); - EXPECT_EQ("", event3.getValues()[1].mValue.str_value); - EXPECT_EQ(0x2010182, event3.getValues()[1].mField.getField()); - EXPECT_EQ(5, event3.getValues()[2].mValue.int_value); - EXPECT_EQ(0x2010201, event3.getValues()[2].mField.getField()); - EXPECT_EQ("", event3.getValues()[3].mValue.str_value); - EXPECT_EQ(0x2018282, event3.getValues()[3].mField.getField()); - EXPECT_EQ(6, event3.getValues()[4].mValue.int_value); - EXPECT_EQ(0x20000, event3.getValues()[4].mField.getField()); - EXPECT_EQ(10, event3.getValues()[5].mValue.long_value); - EXPECT_EQ(0x30000, event3.getValues()[5].mField.getField()); -} - TEST(LogEventTest, TestBinaryFieldAtom) { Atom launcherAtom; auto launcher_event = launcherAtom.mutable_launcher_event(); diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp index 2b0590d11f54..2576cf5b1339 100644 --- a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp @@ -116,7 +116,7 @@ TEST_F(StatsCallbackPullerTest, PullSuccess) { pullSuccess = true; values.push_back(value); - StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {}); vector<std::shared_ptr<LogEvent>> dataHolder; int64_t startTimeNs = getElapsedRealtimeNs(); @@ -137,7 +137,7 @@ TEST_F(StatsCallbackPullerTest, PullFail) { int64_t value = 1234; values.push_back(value); - StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {}); vector<std::shared_ptr<LogEvent>> dataHolder; EXPECT_FALSE(puller.PullInternal(&dataHolder)); @@ -152,7 +152,7 @@ TEST_F(StatsCallbackPullerTest, PullTimeout) { int64_t value = 4321; values.push_back(value); - StatsCallbackPuller puller(pullTagId, cb, pullTimeoutNs); + StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {}); vector<std::shared_ptr<LogEvent>> dataHolder; int64_t startTimeNs = getElapsedRealtimeNs(); diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp index c40719a17f62..f42356a4c805 100644 --- a/cmds/statsd/tests/external/StatsPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsPuller_test.cpp @@ -45,7 +45,7 @@ long pullDelayNs; class FakePuller : public StatsPuller { public: - FakePuller() : StatsPuller(pullTagId){}; + FakePuller() : StatsPuller(pullTagId, /*coolDown=*/NS_PER_SEC, /*timeout=*/NS_PER_SEC / 2){}; private: bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override { diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index 673082834e18..c25e6576fb90 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -34,8 +34,9 @@ using testing::Contains; /* * Test merge isolated and host uid */ - +namespace { int uidAtomTagId = android::util::CPU_CLUSTER_TIME; +const vector<int> uidAdditiveFields = {3}; int nonUidAtomTagId = android::util::SYSTEM_UPTIME; int timestamp = 1234; int isolatedUid = 30; @@ -57,6 +58,7 @@ void extractIntoVector(vector<shared_ptr<LogEvent>> events, ret.push_back(vec); } } +} // anonymous namespace TEST(puller_util, MergeNoDimension) { vector<shared_ptr<LogEvent>> inputData; @@ -81,7 +83,7 @@ TEST(puller_util, MergeNoDimension) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -121,7 +123,7 @@ TEST(puller_util, MergeWithDimension) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -155,7 +157,7 @@ TEST(puller_util, NoMergeHostUidOnly) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); // 20->32->31 // 20->22->21 @@ -191,7 +193,7 @@ TEST(puller_util, IsolatedUidOnly) { .WillRepeatedly(Return(hostUid)); EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))) .WillRepeatedly(ReturnArg<0>()); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); // 20->32->31 // 20->22->21 @@ -232,7 +234,7 @@ TEST(puller_util, MultipleIsolatedUidToOneHostUid) { sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid)); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields); vector<vector<int>> actual; extractIntoVector(inputData, actual); @@ -257,7 +259,7 @@ TEST(puller_util, NoNeedToMerge) { inputData.push_back(event); sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>(); - mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId); + mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/); EXPECT_EQ(2, (int)inputData.size()); } diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp index 9e15e99781d6..b91e5a0ad3a1 100644 --- a/cmds/statsd/tests/storage/StorageManager_test.cpp +++ b/cmds/statsd/tests/storage/StorageManager_test.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <android-base/unique_fd.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <stdio.h> diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 4aaf72728cbf..e649c303541a 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -1515,7 +1515,6 @@ HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityDestroyed(Landroid/os/ HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityIdle(Landroid/os/IBinder;Landroid/content/res/Configuration;Z)V HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityPaused(Landroid/os/IBinder;)V HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityResumed(Landroid/os/IBinder;)V -HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activitySlept(Landroid/os/IBinder;)V HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityStopped(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/os/PersistableBundle;Ljava/lang/CharSequence;)V HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->activityTopResumedStateLost()V HSPLandroid/app/IActivityTaskManager$Stub$Proxy;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z diff --git a/core/java/Android.bp b/core/java/Android.bp index 9a8e130436f8..fb27f74211fb 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -7,8 +7,3 @@ filegroup { name: "IDropBoxManagerService.aidl", srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"], } - -filegroup { - name: "ICarStatsService.aidl", - srcs: ["com/android/internal/car/ICarStatsService.aidl"], -} diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index ee6ccc2f5cd7..7722dc318fd7 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -310,13 +310,11 @@ public abstract class AccessibilityService extends Service { /** * The user has performed a double tap gesture on the touch screen. - * @hide */ public static final int GESTURE_DOUBLE_TAP = 17; /** * The user has performed a double tap and hold gesture on the touch screen. - * @hide */ public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 12f2c3b17c96..82c7635fa5e3 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -341,6 +341,26 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400; + /** + * This flag requests that when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, + * double tap and double tap and hold gestures are dispatched to the service rather than being + * handled by the framework. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this + * flag has no effect. + * + * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + */ + public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x0000800; + + /** + * This flag requests that when when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, + * multi-finger gestures are also enabled. As a consequence, two-finger bypass gestures will be + * disabled. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this flag has no + * effect. + * + * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + */ + public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000; + /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -1221,6 +1241,10 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; + case FLAG_SERVICE_HANDLES_DOUBLE_TAP: + return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; + case FLAG_REQUEST_MULTI_FINGER_GESTURES: + return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; case FLAG_REPORT_VIEW_IDS: diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d952be5218a4..d8b5e7f3b5b0 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -45,6 +45,7 @@ import android.content.CursorLoader; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; +import android.content.LocusId; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -1025,6 +1026,39 @@ public class Activity extends ContextThemeWrapper mIntent = newIntent; } + /** + * Sets the {@link android.content.LocusId} for this activity. The locus id + * helps identify different instances of the same {@code Activity} class. + * <p> For example, a locus id based on a specific conversation could be set on a + * conversation app's chat {@code Activity}. The system can then use this locus id + * along with app's contents to provide ranking signals in various UI surfaces + * including sharing, notifications, shortcuts and so on. + * <p> It is recommended to set the same locus id in the shortcut's locus id using + * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(android.content.LocusId) + * setLocusId} + * so that the system can learn appropriate ranking signals linking the activity's + * locus id with the matching shortcut. + * + * @param locusId a unique, stable id that identifies this {@code Activity} instance from + * others. This can be linked to a shortcut using + * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(android.content.LocusId) + * setLocusId} with the same locus id string. + * @param bundle extras set or updated as part of this locus context. This may help provide + * additional metadata such as URLs, conversation participants specific to this + * {@code Activity}'s context. + * + * @see android.view.contentcapture.ContentCaptureManager + * @see android.view.contentcapture.ContentCaptureContext + */ + public void setLocusContext(@Nullable LocusId locusId, @Nullable Bundle bundle) { + try { + ActivityManager.getService().setActivityLocusContext(mComponent, locusId, mToken); + } catch (RemoteException re) { + re.rethrowFromSystemServer(); + } + // TODO(b/147750355): Pass locusId and bundle to the Content Capture. + } + /** Return the application that owns this activity. */ public final Application getApplication() { return mApplication; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index f7c4d96d0d40..206c7710c12f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -73,6 +73,7 @@ import android.util.DisplayMetrics; import android.util.Singleton; import android.util.Size; import android.view.IWindowContainer; +import android.view.Surface; import com.android.internal.app.LocalePicker; import com.android.internal.app.procstats.ProcessStats; @@ -601,6 +602,22 @@ public class ActivityManager { public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION | PROCESS_CAPABILITY_FOREGROUND_CAMERA | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; + /** + * All explicit capabilities. These are capabilities that need to be specified from manifest + * file. + * @hide + */ + @TestApi + public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = + PROCESS_CAPABILITY_FOREGROUND_LOCATION; + + /** + * All implicit capabilities. There are capabilities that process automatically have. + * @hide + */ + @TestApi + public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = PROCESS_CAPABILITY_FOREGROUND_CAMERA + | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; // NOTE: If PROCESS_STATEs are added, then new fields must be added // to frameworks/base/core/proto/android/app/enums.proto and the following method must @@ -1928,7 +1945,12 @@ public class ActivityManager { // Top activity in task when snapshot was taken private final ComponentName mTopActivityComponent; private final GraphicBuffer mSnapshot; + /** Indicates whether task was in landscape or portrait */ + @Configuration.Orientation private final int mOrientation; + /** See {@link android.view.Surface.Rotation} */ + @Surface.Rotation + private int mRotation; private final Rect mContentInsets; // Whether this snapshot is a down-sampled version of the full resolution, used mainly for // low-ram devices @@ -1945,7 +1967,7 @@ public class ActivityManager { public TaskSnapshot(long id, @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot, - @NonNull ColorSpace colorSpace, int orientation, Rect contentInsets, + @NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets, boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode, int systemUiVisibility, boolean isTranslucent) { mId = id; @@ -1954,6 +1976,7 @@ public class ActivityManager { mColorSpace = colorSpace.getId() < 0 ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; mOrientation = orientation; + mRotation = rotation; mContentInsets = new Rect(contentInsets); mReducedResolution = reducedResolution; mScale = scale; @@ -1972,6 +1995,7 @@ public class ActivityManager { ? ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]) : ColorSpace.get(ColorSpace.Named.SRGB); mOrientation = source.readInt(); + mRotation = source.readInt(); mContentInsets = source.readParcelable(null /* classLoader */); mReducedResolution = source.readBoolean(); mScale = source.readFloat(); @@ -2019,6 +2043,13 @@ public class ActivityManager { } /** + * @return The screen rotation the screenshot was taken in. + */ + public int getRotation() { + return mRotation; + } + + /** * @return The system/content insets on the snapshot. These can be clipped off in order to * remove any areas behind system bars in the snapshot. */ @@ -2087,6 +2118,7 @@ public class ActivityManager { dest.writeParcelable(mSnapshot, 0); dest.writeInt(mColorSpace.getId()); dest.writeInt(mOrientation); + dest.writeInt(mRotation); dest.writeParcelable(mContentInsets, 0); dest.writeBoolean(mReducedResolution); dest.writeFloat(mScale); @@ -2106,6 +2138,7 @@ public class ActivityManager { + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + " mColorSpace=" + mColorSpace.toString() + " mOrientation=" + mOrientation + + " mRotation=" + mRotation + " mContentInsets=" + mContentInsets.toShortString() + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode @@ -2129,6 +2162,7 @@ public class ActivityManager { private GraphicBuffer mSnapshot; private ColorSpace mColorSpace; private int mOrientation; + private int mRotation; private Rect mContentInsets; private boolean mReducedResolution; private float mScaleFraction; @@ -2163,6 +2197,11 @@ public class ActivityManager { return this; } + public Builder setRotation(int rotation) { + mRotation = rotation; + return this; + } + public Builder setContentInsets(Rect contentInsets) { mContentInsets = contentInsets; return this; @@ -2218,6 +2257,7 @@ public class ActivityManager { mSnapshot, mColorSpace, mOrientation, + mRotation, mContentInsets, mReducedResolution, mScaleFraction, diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 4f3e8ec9fb51..4e47594b6196 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -367,4 +367,20 @@ public abstract class ActivityManagerInternal { * Unregisters the specified {@code processObserver}. */ public abstract void unregisterProcessObserver(IProcessObserver processObserver); + + /** + * Checks if there is an unfinished instrumentation that targets the given uid. + * + * @param uid The uid to be checked for + * + * @return True, if there is an instrumentation whose target application uid matches the given + * uid, false otherwise + */ + public abstract boolean isUidCurrentlyInstrumented(int uid); + + /** + * Show a debug toast, asking user to file a bugreport. + */ + // TODO: remove this toast after feature development is done + public abstract void showWhileInUseDebugToast(int uid, int op, int mode); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 48f0087f6b30..d90e81f09800 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -926,10 +926,6 @@ public final class ActivityThread extends ClientTransactionHandler { private class ApplicationThread extends IApplicationThread.Stub { private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; - public final void scheduleSleeping(IBinder token, boolean sleeping) { - sendMessage(H.SLEEPING, token, sleeping ? 1 : 0); - } - public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean sync, int sendingUser, int processState) { @@ -1857,7 +1853,6 @@ public final class ActivityThread extends ClientTransactionHandler { case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; - case SLEEPING: return "SLEEPING"; case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS"; case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO"; case DUMP_PROVIDER: return "DUMP_PROVIDER"; @@ -1987,11 +1982,6 @@ public final class ActivityThread extends ClientTransactionHandler { case DUMP_PROVIDER: handleDumpProvider((DumpComponentInfo)msg.obj); break; - case SLEEPING: - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "sleeping"); - handleSleeping((IBinder)msg.obj, msg.arg1 != 0); - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); - break; case SET_CORE_SETTINGS: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setCoreSettings"); handleSetCoreSettings((Bundle) msg.obj); @@ -4857,41 +4847,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - // TODO: This method should be changed to use {@link #performStopActivityInner} to perform to - // stop operation on the activity to reduce code duplication and the chance of fixing a bug in - // one place and missing the other. - private void handleSleeping(IBinder token, boolean sleeping) { - ActivityClientRecord r = mActivities.get(token); - - if (r == null) { - Log.w(TAG, "handleSleeping: no activity for token " + token); - return; - } - - if (sleeping) { - if (!r.stopped && !r.isPreHoneycomb()) { - callActivityOnStop(r, true /* saveState */, "sleeping"); - } - - // Make sure any pending writes are now committed. - if (!r.isPreHoneycomb()) { - QueuedWork.waitToFinish(); - } - - // Tell activity manager we slept. - try { - ActivityTaskManager.getService().activitySlept(r.token); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - } else { - if (r.stopped && r.activity.mVisibleFromServer) { - r.activity.performRestart(true /* start */, "handleSleeping"); - r.setState(ON_START); - } - } - } - private void handleSetCoreSettings(Bundle coreSettings) { synchronized (mResourcesManager) { mCoreSettings = coreSettings; diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 099037c02bbb..9958c6a31027 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -18,6 +18,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; +import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.util.function.HexFunction; @@ -82,4 +83,12 @@ public abstract class AppOpsManagerInternal { * access to app ops for their user. */ public abstract void setDeviceAndProfileOwners(SparseIntArray owners); + + /** + * Update if the list of AppWidget becomes visible/invisible. + * @param uidPackageNames uid to packageName map. + * @param visible true for visible, false for invisible. + */ + public abstract void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, + boolean visible); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 4e6319db97f4..c09aa1ff05a8 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -131,7 +131,7 @@ public class ApplicationPackageManager extends PackageManager { private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB // Default flags to use with PackageManager when no flags are given. - private final static int sDefaultFlags = PackageManager.GET_SHARED_LIBRARY_FILES; + private static final int sDefaultFlags = GET_SHARED_LIBRARY_FILES; // Name of the resource which provides background permission button string public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS = @@ -907,7 +907,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSigningCertificate( - String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) { + String packageName, byte[] certificate, @CertificateInputType int type) { try { return mPM.hasSigningCertificate(packageName, certificate, type); } catch (RemoteException e) { @@ -917,7 +917,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSigningCertificate( - int uid, byte[] certificate, @PackageManager.CertificateInputType int type) { + int uid, byte[] certificate, @CertificateInputType int type) { try { return mPM.hasUidSigningCertificate(uid, certificate, type); } catch (RemoteException e) { @@ -1464,8 +1464,7 @@ public class ApplicationPackageManager extends PackageManager { return getActivityIcon(intent.getComponent()); } - ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + ResolveInfo info = resolveActivity(intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadIcon(this); } @@ -1500,7 +1499,7 @@ public class ApplicationPackageManager extends PackageManager { } ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadBanner(this); } @@ -1532,8 +1531,7 @@ public class ApplicationPackageManager extends PackageManager { return getActivityLogo(intent.getComponent()); } - ResolveInfo info = resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + ResolveInfo info = resolveActivity(intent, MATCH_DEFAULT_ONLY); if (info != null) { return info.activityInfo.loadLogo(this); } @@ -2017,7 +2015,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int installExistingPackage(String packageName) throws NameNotFoundException { - return installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN); + return installExistingPackage(packageName, INSTALL_REASON_UNKNOWN); } @Override @@ -2029,7 +2027,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int installExistingPackageAsUser(String packageName, int userId) throws NameNotFoundException { - return installExistingPackageAsUser(packageName, PackageManager.INSTALL_REASON_UNKNOWN, + return installExistingPackageAsUser(packageName, INSTALL_REASON_UNKNOWN, userId); } @@ -2404,7 +2402,7 @@ public class ApplicationPackageManager extends PackageManager { public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, int userId) { try { - mPM.deletePackageAsUser(packageName, PackageManager.VERSION_CODE_HIGHEST, + mPM.deletePackageAsUser(packageName, VERSION_CODE_HIGHEST, observer, userId, flags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2651,11 +2649,11 @@ public class ApplicationPackageManager extends PackageManager { public void setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled) { try { ComponentName componentName = new ComponentName(packageName, - PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + APP_DETAILS_ACTIVITY_CLASS_NAME); mPM.setComponentEnabledSetting(componentName, enabled - ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP, getUserId()); + ? COMPONENT_ENABLED_STATE_DEFAULT + : COMPONENT_ENABLED_STATE_DISABLED, + DONT_KILL_APP, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2665,10 +2663,10 @@ public class ApplicationPackageManager extends PackageManager { public boolean getSyntheticAppDetailsActivityEnabled(String packageName) { try { ComponentName componentName = new ComponentName(packageName, - PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME); + APP_DETAILS_ACTIVITY_CLASS_NAME); int state = mPM.getComponentEnabledSetting(componentName, getUserId()); - return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED - || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + return state == COMPONENT_ENABLED_STATE_ENABLED + || state == COMPONENT_ENABLED_STATE_DEFAULT; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2744,6 +2742,30 @@ public class ApplicationPackageManager extends PackageManager { /** @hide */ @Override + public void setSystemAppState(String packageName, @SystemAppState int state) { + try { + switch (state) { + case SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN: + mPM.setSystemAppHiddenUntilInstalled(packageName, true); + break; + case SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE: + mPM.setSystemAppHiddenUntilInstalled(packageName, false); + break; + case SYSTEM_APP_STATE_INSTALLED: + mPM.setSystemAppInstallState(packageName, true, getUserId()); + break; + case SYSTEM_APP_STATE_UNINSTALLED: + mPM.setSystemAppInstallState(packageName, false, getUserId()); + break; + default: + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @Override public KeySet getKeySetByAlias(String packageName, String alias) { Objects.requireNonNull(packageName); Objects.requireNonNull(alias); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 7d04ca0afe7e..3ffd7c70b40d 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -53,6 +53,7 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; +import android.content.LocusId; import android.graphics.Bitmap; import android.graphics.GraphicBuffer; import android.graphics.Point; @@ -637,4 +638,13 @@ interface IActivityManager { * and the given process is imperceptible. */ void killProcessesWhenImperceptible(in int[] pids, String reason); + + /** + * Set locus context for a given activity. + * @param activity + * @param locusId a unique, stable id that identifies this activity instance from others. + * @param appToken ActivityRecord's appToken. + */ + void setActivityLocusContext(in ComponentName activity, in LocusId locusId, + in IBinder appToken); } diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index e5c046c2376c..85fa7c1cdb54 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -141,7 +141,6 @@ interface IActivityTaskManager { in PersistableBundle persistentState, in CharSequence description); oneway void activityDestroyed(in IBinder token); void activityRelaunched(in IBinder token); - oneway void activitySlept(in IBinder token); int getFrontActivityScreenCompatMode(); void setFrontActivityScreenCompatMode(int mode); String getCallingPackage(in IBinder token); diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 51a64fff7c45..c33c515f062c 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -91,7 +91,6 @@ oneway interface IApplicationThread { int resultCode, in String data, in Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState); void scheduleLowMemory(); - void scheduleSleeping(IBinder token, boolean sleeping); void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); void setSchedulingGroup(int group); void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index d665f336ec1d..4b1ba0278682 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -18,6 +18,7 @@ package android.app; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -45,8 +46,7 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); - // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text) - void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId); + void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback); void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId); void cancelToast(String pkg, IBinder token); void finishToken(String pkg, IBinder token); diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.aidl b/core/java/android/app/ITransientNotificationCallback.aidl index 155219038d7b..abe254f2d16a 100644 --- a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.aidl +++ b/core/java/android/app/ITransientNotificationCallback.aidl @@ -1,6 +1,5 @@ /* - * - * Copyright 2019, The Android Open Source Project + * 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. @@ -15,6 +14,14 @@ * limitations under the License. */ -package android.telephony.ims; +package android.app; -parcelable RcsFileTransferCreationParams; +/** + * Callback object to be called when the associated toast is shown or hidden. + * + * @hide + */ +oneway interface ITransientNotificationCallback { + void onToastShown(); + void onToastHidden(); +} diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 6518652f6e91..4b0cadbd9c65 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -17,19 +17,21 @@ package android.app; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.app.admin.DevicePolicyManager; +import android.app.admin.PasswordMetrics; import android.app.trust.ITrustManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.hardware.biometrics.BiometricPrompt; import android.os.Binder; import android.os.Build; import android.os.IBinder; @@ -46,7 +48,11 @@ import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternView; +import com.android.internal.widget.LockscreenCredential; +import java.nio.charset.Charset; +import java.util.Arrays; import java.util.List; /** @@ -134,7 +140,7 @@ public class KeyguardManager { * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. * * @return the intent for launching the activity or null if no password is required. - * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)} + * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean) */ @Deprecated @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) @@ -655,4 +661,151 @@ public class KeyguardManager { } } + + private boolean checkInitialLockMethodUsage() { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.SET_INITIAL_LOCK) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires SET_INITIAL_LOCK permission."); + } + if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + return false; + } + return true; + } + + /** + * Determine if a given password is valid based off its lock type and expected complexity level. + * + * @param isPin - whether this is a PIN-type password (only digits) + * @param password - password to validate + * @param complexity - complexity level imposed by the requester + * as defined in {@code DevicePolicyManager.PasswordComplexity} + * @return true if the password is valid, false otherwise + * @hide + */ + @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) + @SystemApi + public boolean validateLockPasswordComplexity( + boolean isPin, @NonNull byte[] password, int complexity) { + if (!checkInitialLockMethodUsage()) { + return false; + } + complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); + // TODO: b/131755827 add devicePolicyManager support for Auto + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + PasswordMetrics adminMetrics = + devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); + + return PasswordMetrics.validatePassword( + adminMetrics, complexity, isPin, password).size() == 0; + } + + /** + * Determine the minimum allowable length for a lock type for a given complexity level. + * + * @param isPin - whether this is a PIN-type password (only digits) + * @param complexity - complexity level imposed by the requester + * as defined in {@code DevicePolicyManager.PasswordComplexity} + * @return minimum allowable password length + * @hide + */ + @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) + @SystemApi + public int getMinLockLength(boolean isPin, int complexity) { + if (!checkInitialLockMethodUsage()) { + return -1; + } + complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); + // TODO: b/131755827 add devicePolicyManager support for Auto + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + PasswordMetrics adminMetrics = + devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); + PasswordMetrics minMetrics = + PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity); + return minMetrics.length; + } + + /** + * Set the lockscreen password after validating against its expected complexity level. + * + * @param lockType - type of lock as specified in {@link LockTypes} + * @param password - password to validate + * @param complexity - complexity level imposed by the requester + * as defined in {@code DevicePolicyManager.PasswordComplexity} + * @return true if the lock is successfully set, false otherwise + * @hide + */ + @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) + @SystemApi + public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, int complexity) { + if (!checkInitialLockMethodUsage()) { + return false; + } + + LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); + int userId = mContext.getUserId(); + if (isDeviceSecure(userId)) { + Log.e(TAG, "Password already set, rejecting call to setLock"); + return false; + } + if (!validateLockPasswordComplexity(lockType != LockTypes.PASSWORD, password, complexity)) { + Log.e(TAG, "Password is not valid, rejecting call to setLock"); + return false; + } + boolean success = false; + try { + switch (lockType) { + case LockTypes.PASSWORD: + CharSequence passwordStr = new String(password, Charset.forName("UTF-8")); + lockPatternUtils.setLockCredential( + LockscreenCredential.createPassword(passwordStr), + /* savedPassword= */ LockscreenCredential.createNone(), + userId); + success = true; + break; + case LockTypes.PIN: + CharSequence pinStr = new String(password); + lockPatternUtils.setLockCredential( + LockscreenCredential.createPin(pinStr), + /* savedPassword= */ LockscreenCredential.createNone(), + userId); + success = true; + break; + case LockTypes.PATTERN: + List<LockPatternView.Cell> pattern = + LockPatternUtils.byteArrayToPattern(password); + lockPatternUtils.setLockCredential( + LockscreenCredential.createPattern(pattern), + /* savedPassword= */ LockscreenCredential.createNone(), + userId); + pattern.clear(); + success = true; + break; + default: + Log.e(TAG, "Unknown lock type, returning a failure"); + } + } catch (Exception e) { + Log.e(TAG, "Save lock exception", e); + success = false; + } finally { + Arrays.fill(password, (byte) 0); + } + return success; + } + + /** + * Available lock types + */ + @IntDef({ + LockTypes.PASSWORD, + LockTypes.PIN, + LockTypes.PATTERN + }) + @interface LockTypes { + int PASSWORD = 0; + int PIN = 1; + int PATTERN = 2; + } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f4dc0bffd5ed..d1b5a83e7142 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8855,6 +8855,49 @@ public class DevicePolicyManager { } /** + * Called by device owners to request a location provider to change its allowed state. For a + * provider to be enabled requires both that the master location setting is enabled, and that + * the provider itself is allowed. Most location providers are always allowed. Some location + * providers may have user consents or terms and conditions that must be accepted, or some other + * type of blocker before they are allowed however. Every location provider is responsible for + * its own allowed state. + * + * <p>This method requests that a location provider change its allowed state. For providers that + * are always allowed and have no state to change, this will have no effect. If the provider + * does require some consent, terms and conditions, or other blocking state, using this API + * implies that the device owner is agreeing/disagreeing to any consents, terms and conditions, + * etc, and the provider should make a best effort to adjust it's allowed state accordingly. + * + * <p>Location providers are generally only responsible for the current user, and callers must + * assume that this method will only affect provider state for the current user. Callers are + * responsible for tracking current user changes and re-updating provider state as necessary. + * + * <p>While providers are expected to make a best effort to honor this request, it is not a + * given that all providers will support such a request. If a provider does change its state as + * a result of this request, that may happen asynchronously after some delay. Test location + * providers set through {@link android.location.LocationManager#addTestProvider} will respond + * to this request to aide in testing. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with + * @param provider A location provider as listed by + * {@link android.location.LocationManager#getAllProviders()} + * @param providerAllowed Whether the location provider is being requested to enable or disable + * itself + * @throws SecurityException if {@code admin} is not a device owner. + */ + public void requestSetLocationProviderAllowed(@NonNull ComponentName admin, + @NonNull String provider, boolean providerAllowed) { + throwIfParentInstance("requestSetLocationProviderAllowed"); + if (mService != null) { + try { + mService.requestSetLocationProviderAllowed(admin, provider, providerAllowed); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** * Called by profile or device owners to update {@link android.provider.Settings.Secure} * settings. Validation that the value of the setting is in the correct form for the setting * type should be performed by the caller. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index ab0598b76b82..e3dba310ab44 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -270,6 +270,7 @@ interface IDevicePolicyManager { boolean isLockdownAdminConfiguredNetworks(in ComponentName who); void setLocationEnabled(in ComponentName who, boolean locationEnabled); + void requestSetLocationProviderAllowed(in ComponentName who, in String provider, boolean providerAllowed); boolean setTime(in ComponentName who, long millis); boolean setTimeZone(in ComponentName who, String timeZone); diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 0ecfca74b26e..86ebb47400c7 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -682,6 +682,11 @@ public final class PasswordMetrics implements Parcelable { * * TODO: move to PasswordPolicy */ + public static PasswordMetrics applyComplexity( + PasswordMetrics adminMetrics, boolean isPin, int complexity) { + return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity)); + } + private static PasswordMetrics applyComplexity( PasswordMetrics adminMetrics, boolean isPin, ComplexityBucket bucket) { final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics); diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 6ab880dfb36d..ab71e73fd58c 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -290,10 +290,16 @@ public final class UsageEvents implements Parcelable { public static final int USER_STOPPED = 29; /** + * An event type denoting that new locusId has been set for a given activity. + * @hide + */ + public static final int LOCUS_ID_SET = 30; + + /** * Keep in sync with the greatest event type value. * @hide */ - public static final int MAX_EVENT_TYPE = 29; + public static final int MAX_EVENT_TYPE = 30; /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; @@ -436,6 +442,18 @@ public final class UsageEvents implements Parcelable { */ public int mNotificationChannelIdToken = UNASSIGNED_TOKEN; + /** + * LocusId. + * Currently LocusId only present for {@link #LOCUS_ID_SET} event types. + * {@hide} + */ + public String mLocusId; + + /** + * {@hide} + */ + public int mLocusIdToken = UNASSIGNED_TOKEN; + /** @hide */ @EventFlags public int mFlags; @@ -609,6 +627,16 @@ public final class UsageEvents implements Parcelable { return ret; } + /** + * Returns the locusId for this event if the event is of type {@link #LOCUS_ID_SET}, + * otherwise it returns null. + * @hide + */ + @Nullable + public String getLocusId() { + return mLocusId; + } + private void copyFrom(Event orig) { mPackage = orig.mPackage; mClass = orig.mClass; @@ -625,6 +653,7 @@ public final class UsageEvents implements Parcelable { mFlags = orig.mFlags; mBucketAndReason = orig.mBucketAndReason; mNotificationChannelId = orig.mNotificationChannelId; + mLocusId = orig.mLocusId; } } @@ -823,6 +852,9 @@ public final class UsageEvents implements Parcelable { case Event.NOTIFICATION_INTERRUPTION: p.writeString(event.mNotificationChannelId); break; + case Event.LOCUS_ID_SET: + p.writeString(event.mLocusId); + break; } p.writeInt(event.mFlags); } @@ -871,6 +903,7 @@ public final class UsageEvents implements Parcelable { eventOut.mContentType = null; eventOut.mContentAnnotations = null; eventOut.mNotificationChannelId = null; + eventOut.mLocusId = null; switch (eventOut.mEventType) { case Event.CONFIGURATION_CHANGE: @@ -891,6 +924,9 @@ public final class UsageEvents implements Parcelable { case Event.NOTIFICATION_INTERRUPTION: eventOut.mNotificationChannelId = p.readString(); break; + case Event.LOCUS_ID_SET: + eventOut.mLocusId = p.readString(); + break; } eventOut.mFlags = p.readInt(); } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index e7513544a886..e24b0403cd6a 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -3236,18 +3236,6 @@ public final class BluetoothAdapter { } /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, listenUsingL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingL2capCoc(int transport) - throws IOException { - Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel"); - return listenUsingL2capChannel(); - } - - /** * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The * supported Bluetooth transport is LE only. @@ -3294,19 +3282,6 @@ public final class BluetoothAdapter { } /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, listenUsingInsecureL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) - throws IOException { - Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, " - + "listenUsingInsecureL2capChannel"); - return listenUsingInsecureL2capChannel(); - } - - /** * Register a {@link #OnMetadataChangedListener} to receive update about metadata * changes for this {@link BluetoothDevice}. * Registration must be done when Bluetooth is ON and will last until diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 9fe4dd66b874..12dc814c3416 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -2172,17 +2172,6 @@ public final class BluetoothDevice implements Parcelable { } /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, createL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException { - Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel"); - return createL2capChannel(psm); - } - - /** * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can * be used to start a secure outgoing connection to the remote device with the same dynamic * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. @@ -2213,17 +2202,6 @@ public final class BluetoothDevice implements Parcelable { } /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, createInsecureL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException { - Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel"); - return createInsecureL2capChannel(psm); - } - - /** * Set a keyed metadata of this {@link BluetoothDevice} to a * {@link String} value. * Only bonded devices's metadata will be persisted across Bluetooth diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 58a0ea56a65f..a0d5c108869e 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4139,16 +4139,16 @@ public abstract class Context { public static final String LOWPAN_SERVICE = "lowpan"; /** - * Use with {@link #getSystemService(String)} to retrieve a {@link - * android.net.EthernetManager} for handling management of - * Ethernet access. + * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager} + * for handling management of Ethernet access. * * @see #getSystemService(String) * @see android.net.EthernetManager * * @hide */ - @UnsupportedAppUsage + @SystemApi + @TestApi public static final String ETHERNET_SERVICE = "ethernet"; /** @@ -5032,10 +5032,7 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve an * {@link android.telephony.ims.ImsManager}. - * @hide */ - @SystemApi - @TestApi public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 5852a93ea221..acffec98b2fc 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -36,6 +36,7 @@ import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.pm.SuspendDialogInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; @@ -2667,6 +2668,34 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.SHOW_SUSPENDED_APP_DETAILS"; /** + * Broadcast Action: Sent to indicate that the user unsuspended a package. + * + * <p>This can happen when the user taps on the neutral button of the + * {@linkplain SuspendDialogInfo suspend-dialog} which was created by using + * {@link SuspendDialogInfo#BUTTON_ACTION_UNSUSPEND}. This broadcast is only sent to the + * suspending app that originally specified this dialog while calling + * {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, + * PersistableBundle, SuspendDialogInfo)}. + * + * <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the package that just + * got unsuspended. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. <em>This will be delivered to {@link BroadcastReceiver} components declared in + * the manifest.</em> + * + * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, + * PersistableBundle, SuspendDialogInfo) + * @see PackageManager#isPackageSuspended() + * @see SuspendDialogInfo#BUTTON_ACTION_MORE_DETAILS + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PACKAGE_UNSUSPENDED_MANUALLY = + "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY"; + + /** * Broadcast Action: Sent to a package that has been unsuspended. * * <p class="note">This is a protected intent that can only be sent @@ -4533,12 +4562,6 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost"; /** - * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state. - * @hide - */ - public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE"; - - /** * The name of the extra used to define the text to be processed, as a * CharSequence. Note that this may be a styled CharSequence, so you must use * {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it. diff --git a/telephony/java/android/telephony/ims/RcsMessageSnippet.aidl b/core/java/android/content/LocusId.aidl index 99b8eb704e00..eb98db06ccbf 100644 --- a/telephony/java/android/telephony/ims/RcsMessageSnippet.aidl +++ b/core/java/android/content/LocusId.aidl @@ -1,6 +1,5 @@ -/* - * - * Copyright 2019, The Android Open Source Project +/** + * 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. @@ -15,6 +14,6 @@ * limitations under the License. */ -package android.telephony.ims; +package android.content; -parcelable RcsMessageSnippet; +parcelable LocusId; diff --git a/core/java/android/content/integrity/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java index 85af8813fa94..351edc92888d 100644 --- a/core/java/android/content/integrity/AppInstallMetadata.java +++ b/core/java/android/content/integrity/AppInstallMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -17,10 +17,6 @@ package android.content.integrity; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; - -import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; @@ -34,8 +30,6 @@ import java.util.Objects; * * @hide */ -@SystemApi -@VisibleForTesting public final class AppInstallMetadata { private final String mPackageName; // Raw string encoding for the SHA-256 hash of the certificate of the app. @@ -43,7 +37,7 @@ public final class AppInstallMetadata { private final String mInstallerName; // Raw string encoding for the SHA-256 hash of the certificate of the installer. private final String mInstallerCertificate; - private final int mVersionCode; + private final long mVersionCode; private final boolean mIsPreInstalled; private AppInstallMetadata(Builder builder) { @@ -65,18 +59,18 @@ public final class AppInstallMetadata { return mAppCertificate; } - @Nullable + @NonNull public String getInstallerName() { return mInstallerName; } - @Nullable + @NonNull public String getInstallerCertificate() { return mInstallerCertificate; } - /** @see AppInstallMetadata.Builder#setVersionCode(int) */ - public int getVersionCode() { + /** @see AppInstallMetadata.Builder#setVersionCode(long) */ + public long getVersionCode() { return mVersionCode; } @@ -104,7 +98,7 @@ public final class AppInstallMetadata { private String mAppCertificate; private String mInstallerName; private String mInstallerCertificate; - private int mVersionCode; + private long mVersionCode; private boolean mIsPreInstalled; /** @@ -163,7 +157,7 @@ public final class AppInstallMetadata { * @see AppInstallMetadata#getVersionCode() */ @NonNull - public Builder setVersionCode(int versionCode) { + public Builder setVersionCode(long versionCode) { this.mVersionCode = versionCode; return this; } diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java index 574a93ff9355..4c10a8f7ad38 100644 --- a/core/java/android/content/integrity/AtomicFormula.java +++ b/core/java/android/content/integrity/AtomicFormula.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -20,15 +20,16 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Objects; /** @@ -38,29 +39,28 @@ import java.util.Objects; * * @hide */ -@SystemApi @VisibleForTesting -public abstract class AtomicFormula implements Formula { - - private static final String TAG = "AtomicFormula"; +public abstract class AtomicFormula extends IntegrityFormula { /** @hide */ @IntDef( value = { - PACKAGE_NAME, - APP_CERTIFICATE, - INSTALLER_NAME, - INSTALLER_CERTIFICATE, - VERSION_CODE, - PRE_INSTALLED, + PACKAGE_NAME, + APP_CERTIFICATE, + INSTALLER_NAME, + INSTALLER_CERTIFICATE, + VERSION_CODE, + PRE_INSTALLED, }) @Retention(RetentionPolicy.SOURCE) - public @interface Key {} + public @interface Key { + } /** @hide */ - @IntDef(value = {EQ, LT, LE, GT, GE}) + @IntDef(value = {EQ, GT, GTE}) @Retention(RetentionPolicy.SOURCE) - public @interface Operator {} + public @interface Operator { + } /** * Package name of the app. @@ -94,7 +94,7 @@ public abstract class AtomicFormula implements Formula { /** * Version code of the app. * - * <p>Can only be used in {@link IntAtomicFormula}. + * <p>Can only be used in {@link LongAtomicFormula}. */ public static final int VERSION_CODE = 4; @@ -106,10 +106,8 @@ public abstract class AtomicFormula implements Formula { public static final int PRE_INSTALLED = 5; public static final int EQ = 0; - public static final int LT = 1; - public static final int LE = 2; - public static final int GT = 3; - public static final int GE = 4; + public static final int GT = 1; + public static final int GTE = 2; private final @Key int mKey; @@ -118,78 +116,99 @@ public abstract class AtomicFormula implements Formula { mKey = key; } - /** An {@link AtomicFormula} with an key and int value. */ - public static final class IntAtomicFormula extends AtomicFormula implements Parcelable { - private final int mValue; - private final @Operator int mOperator; + /** An {@link AtomicFormula} with an key and long value. */ + public static final class LongAtomicFormula extends AtomicFormula implements Parcelable { + private final Long mValue; + private final @Operator Integer mOperator; + + /** + * Constructs an empty {@link LongAtomicFormula}. This should only be used as a base. + * + * <p>This formula will always return false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with long value + */ + public LongAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == VERSION_CODE, + String.format( + "Key %s cannot be used with LongAtomicFormula", keyToString(key))); + mValue = null; + mOperator = null; + } /** - * Constructs a new {@link IntAtomicFormula}. + * Constructs a new {@link LongAtomicFormula}. * * <p>This formula will hold if and only if the corresponding information of an install * specified by {@code key} is of the correct relationship to {@code value} as specified by * {@code operator}. * - * @throws IllegalArgumentException if {@code key} cannot be used with integer value + * @throws IllegalArgumentException if {@code key} cannot be used with long value */ - public IntAtomicFormula(@Key int key, @Operator int operator, int value) { + public LongAtomicFormula(@Key int key, @Operator int operator, long value) { super(key); checkArgument( key == VERSION_CODE, - String.format("Key %s cannot be used with IntAtomicFormula", keyToString(key))); - checkArgument(isValidOperator(operator), - String.format("Unknown operator: %d", operator)); + String.format( + "Key %s cannot be used with LongAtomicFormula", keyToString(key))); + checkArgument( + isValidOperator(operator), String.format("Unknown operator: %d", operator)); mOperator = operator; mValue = value; } - IntAtomicFormula(Parcel in) { + LongAtomicFormula(Parcel in) { super(in.readInt()); - mValue = in.readInt(); + mValue = in.readLong(); mOperator = in.readInt(); } @NonNull - public static final Creator<IntAtomicFormula> CREATOR = - new Creator<IntAtomicFormula>() { + public static final Creator<LongAtomicFormula> CREATOR = + new Creator<LongAtomicFormula>() { @Override - public IntAtomicFormula createFromParcel(Parcel in) { - return new IntAtomicFormula(in); + public LongAtomicFormula createFromParcel(Parcel in) { + return new LongAtomicFormula(in); } @Override - public IntAtomicFormula[] newArray(int size) { - return new IntAtomicFormula[size]; + public LongAtomicFormula[] newArray(int size) { + return new LongAtomicFormula[size]; } }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - int metadataValue = getMetadataValueByKey(appInstallMetadata); + public int getTag() { + return IntegrityFormula.LONG_ATOMIC_FORMULA_TAG; + } + + @Override + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null || mOperator == null) { + return false; + } + + long metadataValue = getLongMetadataValue(appInstallMetadata, getKey()); switch (mOperator) { case EQ: return metadataValue == mValue; - case LE: - return metadataValue <= mValue; - case LT: - return metadataValue < mValue; - case GE: - return metadataValue >= mValue; case GT: return metadataValue > mValue; + case GTE: + return metadataValue >= mValue; default: - Slog.i(TAG, String.format("Unexpected operator %d", mOperator)); - return false; + throw new IllegalArgumentException( + String.format("Unexpected operator %d", mOperator)); } } @Override - public int getTag() { - return Formula.INT_ATOMIC_FORMULA_TAG; - } - - @Override public String toString() { + if (mValue == null || mOperator == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format( "(%s %s %s)", keyToString(getKey()), operatorToString(mOperator), mValue); } @@ -202,7 +221,7 @@ public abstract class AtomicFormula implements Formula { if (o == null || getClass() != o.getClass()) { return false; } - IntAtomicFormula that = (IntAtomicFormula) o; + LongAtomicFormula that = (LongAtomicFormula) o; return getKey() == that.getKey() && mValue == that.mValue && mOperator == that.mOperator; @@ -220,35 +239,35 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null || mOperator == null) { + throw new IllegalStateException("Cannot write an empty LongAtomicFormula."); + } dest.writeInt(getKey()); - dest.writeInt(mValue); + dest.writeLong(mValue); dest.writeInt(mOperator); } - public int getValue() { + public Long getValue() { return mValue; } - public int getOperator() { + public Integer getOperator() { return mOperator; } - private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case VERSION_CODE: - return appInstallMetadata.getVersionCode(); - default: - throw new IllegalStateException( - "Unexpected key in IntAtomicFormula" + getKey()); - } - } - private static boolean isValidOperator(int operator) { return operator == EQ - || operator == LT - || operator == LE || operator == GT - || operator == GE; + || operator == GTE; + } + + private static long getLongMetadataValue(AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.VERSION_CODE: + return appInstallMetadata.getVersionCode(); + default: + throw new IllegalStateException("Unexpected key in IntAtomicFormula" + key); + } } } @@ -256,7 +275,27 @@ public abstract class AtomicFormula implements Formula { public static final class StringAtomicFormula extends AtomicFormula implements Parcelable { private final String mValue; // Indicates whether the value is the actual value or the hashed value. - private final boolean mIsHashedValue; + private final Boolean mIsHashedValue; + + /** + * Constructs an empty {@link StringAtomicFormula}. This should only be used as a base. + * + * <p>An empty formula will always match to false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with string value + */ + public StringAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == PACKAGE_NAME + || key == APP_CERTIFICATE + || key == INSTALLER_CERTIFICATE + || key == INSTALLER_NAME, + String.format( + "Key %s cannot be used with StringAtomicFormula", keyToString(key))); + mValue = null; + mIsHashedValue = null; + } /** * Constructs a new {@link StringAtomicFormula}. @@ -266,9 +305,8 @@ public abstract class AtomicFormula implements Formula { * * @throws IllegalArgumentException if {@code key} cannot be used with string value */ - public StringAtomicFormula(@Key int key, @NonNull String value, boolean isHashedValue) { + public StringAtomicFormula(@Key int key, @NonNull String value, boolean isHashed) { super(key); - mIsHashedValue = isHashedValue; checkArgument( key == PACKAGE_NAME || key == APP_CERTIFICATE @@ -277,6 +315,30 @@ public abstract class AtomicFormula implements Formula { String.format( "Key %s cannot be used with StringAtomicFormula", keyToString(key))); mValue = value; + mIsHashedValue = isHashed; + } + + /** + * Constructs a new {@link StringAtomicFormula} together with handling the necessary + * hashing for the given key. + * + * <p> The value will be hashed with SHA256 and the hex digest will be computed; for + * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value + * is less than 33 characters. + * + * @throws IllegalArgumentException if {@code key} cannot be used with string value. + */ + public StringAtomicFormula(@Key int key, @NonNull String value) { + super(key); + checkArgument( + key == PACKAGE_NAME + || key == APP_CERTIFICATE + || key == INSTALLER_CERTIFICATE + || key == INSTALLER_NAME, + String.format( + "Key %s cannot be used with StringAtomicFormula", keyToString(key))); + mValue = hashValue(key, value); + mIsHashedValue = !mValue.equals(value); } StringAtomicFormula(Parcel in) { @@ -300,18 +362,23 @@ public abstract class AtomicFormula implements Formula { }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - String metadataValue = getMetadataValueByKey(appInstallMetadata); - return metadataValue.equals(mValue); + public int getTag() { + return IntegrityFormula.STRING_ATOMIC_FORMULA_TAG; } @Override - public int getTag() { - return Formula.STRING_ATOMIC_FORMULA_TAG; + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null || mIsHashedValue == null) { + return false; + } + return getStringMetadataValue(appInstallMetadata, getKey()).equals(mValue); } @Override public String toString() { + if (mValue == null || mIsHashedValue == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue); } @@ -339,40 +406,80 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null || mIsHashedValue == null) { + throw new IllegalStateException("Cannot write an empty StringAtomicFormula."); + } dest.writeInt(getKey()); dest.writeStringNoHelper(mValue); dest.writeByte((byte) (mIsHashedValue ? 1 : 0)); } - @NonNull public String getValue() { return mValue; } - public boolean getIsHashedValue() { + public Boolean getIsHashedValue() { return mIsHashedValue; } - private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case PACKAGE_NAME: + private static String getStringMetadataValue( + AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.PACKAGE_NAME: return appInstallMetadata.getPackageName(); - case APP_CERTIFICATE: + case AtomicFormula.APP_CERTIFICATE: return appInstallMetadata.getAppCertificate(); - case INSTALLER_CERTIFICATE: + case AtomicFormula.INSTALLER_CERTIFICATE: return appInstallMetadata.getInstallerCertificate(); - case INSTALLER_NAME: + case AtomicFormula.INSTALLER_NAME: return appInstallMetadata.getInstallerName(); default: throw new IllegalStateException( - "Unexpected key in StringAtomicFormula: " + getKey()); + "Unexpected key in StringAtomicFormula: " + key); + } + } + + private static String hashValue(@Key int key, String value) { + // Hash the string value unless it is a PACKAGE_NAME or INSTALLER_NAME and the value is + // less than 33 characters. + if (value.length() <= 32) { + if (key == PACKAGE_NAME || key == INSTALLER_NAME) { + return value; + } + } + return hash(value); + } + + private static String hash(String value) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + byte[] hashBytes = messageDigest.digest(value.getBytes(StandardCharsets.UTF_8)); + return IntegrityUtils.getHexDigest(hashBytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not found", e); } } } /** An {@link AtomicFormula} with a key and boolean value. */ public static final class BooleanAtomicFormula extends AtomicFormula implements Parcelable { - private final boolean mValue; + private final Boolean mValue; + + /** + * Constructs an empty {@link BooleanAtomicFormula}. This should only be used as a base. + * + * <p>An empty formula will always match to false. + * + * @throws IllegalArgumentException if {@code key} cannot be used with boolean value + */ + public BooleanAtomicFormula(@Key int key) { + super(key); + checkArgument( + key == PRE_INSTALLED, + String.format( + "Key %s cannot be used with BooleanAtomicFormula", keyToString(key))); + mValue = null; + } /** * Constructs a new {@link BooleanAtomicFormula}. @@ -411,18 +518,23 @@ public abstract class AtomicFormula implements Formula { }; @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - boolean metadataValue = getMetadataValueByKey(appInstallMetadata); - return metadataValue == mValue; + public int getTag() { + return IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG; } @Override - public int getTag() { - return Formula.BOOLEAN_ATOMIC_FORMULA_TAG; + public boolean matches(AppInstallMetadata appInstallMetadata) { + if (mValue == null) { + return false; + } + return getBooleanMetadataValue(appInstallMetadata, getKey()) == mValue; } @Override public String toString() { + if (mValue == null) { + return String.format("(%s)", keyToString(getKey())); + } return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue); } @@ -450,21 +562,25 @@ public abstract class AtomicFormula implements Formula { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + if (mValue == null) { + throw new IllegalStateException("Cannot write an empty BooleanAtomicFormula."); + } dest.writeInt(getKey()); dest.writeByte((byte) (mValue ? 1 : 0)); } - public boolean getValue() { + public Boolean getValue() { return mValue; } - private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) { - switch (getKey()) { - case PRE_INSTALLED: + private static boolean getBooleanMetadataValue( + AppInstallMetadata appInstallMetadata, int key) { + switch (key) { + case AtomicFormula.PRE_INSTALLED: return appInstallMetadata.isPreInstalled(); default: throw new IllegalStateException( - "Unexpected key in BooleanAtomicFormula: " + getKey()); + "Unexpected key in BooleanAtomicFormula: " + key); } } } @@ -496,14 +612,10 @@ public abstract class AtomicFormula implements Formula { switch (op) { case EQ: return "EQ"; - case LT: - return "LT"; - case LE: - return "LE"; case GT: return "GT"; - case GE: - return "GE"; + case GTE: + return "GTE"; default: throw new IllegalArgumentException("Unknown operator " + op); } diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java index 2a651d9e90d8..56061df21388 100644 --- a/core/java/android/content/integrity/CompoundFormula.java +++ b/core/java/android/content/integrity/CompoundFormula.java @@ -20,10 +20,8 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -42,16 +40,11 @@ import java.util.Objects; * * @hide */ -@SystemApi @VisibleForTesting -public final class CompoundFormula implements Formula, Parcelable { - private static final String TAG = "OpenFormula"; +public final class CompoundFormula extends IntegrityFormula implements Parcelable { /** @hide */ - @IntDef( - value = { - AND, OR, NOT, - }) + @IntDef(value = {AND, OR, NOT}) @Retention(RetentionPolicy.SOURCE) public @interface Connector {} @@ -65,7 +58,7 @@ public final class CompoundFormula implements Formula, Parcelable { public static final int NOT = 2; private final @Connector int mConnector; - private final @NonNull List<Formula> mFormulas; + private final @NonNull List<IntegrityFormula> mFormulas; @NonNull public static final Creator<CompoundFormula> CREATOR = @@ -85,9 +78,10 @@ public final class CompoundFormula implements Formula, Parcelable { * Create a new formula from operator and operands. * * @throws IllegalArgumentException if the number of operands is not matching the requirements - * for that operator (at least 2 for {@link #AND} and {@link #OR}, 1 for {@link #NOT}). + * for that operator (at least 2 for {@link #AND} and {@link + * #OR}, 1 for {@link #NOT}). */ - public CompoundFormula(@Connector int connector, @NonNull List<Formula> formulas) { + public CompoundFormula(@Connector int connector, List<IntegrityFormula> formulas) { checkArgument( isValidConnector(connector), String.format("Unknown connector: %d", connector)); validateFormulas(connector, formulas); @@ -101,7 +95,7 @@ public final class CompoundFormula implements Formula, Parcelable { checkArgument(length >= 0, "Must have non-negative length. Got " + length); mFormulas = new ArrayList<>(length); for (int i = 0; i < length; i++) { - mFormulas.add(Formula.readFromParcel(in)); + mFormulas.add(IntegrityFormula.readFromParcel(in)); } validateFormulas(mConnector, mFormulas); } @@ -111,33 +105,32 @@ public final class CompoundFormula implements Formula, Parcelable { } @NonNull - public List<Formula> getFormulas() { + public List<IntegrityFormula> getFormulas() { return mFormulas; } @Override - public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) { - switch (mConnector) { + public int getTag() { + return IntegrityFormula.COMPOUND_FORMULA_TAG; + } + + @Override + public boolean matches(AppInstallMetadata appInstallMetadata) { + switch (getConnector()) { case NOT: - return !mFormulas.get(0).isSatisfied(appInstallMetadata); + return !getFormulas().get(0).matches(appInstallMetadata); case AND: - return mFormulas.stream() - .allMatch(formula -> formula.isSatisfied(appInstallMetadata)); + return getFormulas().stream() + .allMatch(formula -> formula.matches(appInstallMetadata)); case OR: - return mFormulas.stream() - .anyMatch(formula -> formula.isSatisfied(appInstallMetadata)); + return getFormulas().stream() + .anyMatch(formula -> formula.matches(appInstallMetadata)); default: - Slog.i(TAG, "Unknown connector " + mConnector); - return false; + throw new IllegalArgumentException("Unknown connector " + getConnector()); } } @Override - public int getTag() { - return Formula.COMPOUND_FORMULA_TAG; - } - - @Override public String toString() { StringBuilder sb = new StringBuilder(); if (mFormulas.size() == 1) { @@ -180,12 +173,13 @@ public final class CompoundFormula implements Formula, Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mConnector); dest.writeInt(mFormulas.size()); - for (Formula formula : mFormulas) { - Formula.writeToParcel(formula, dest, flags); + for (IntegrityFormula formula : mFormulas) { + IntegrityFormula.writeToParcel(formula, dest, flags); } } - private static void validateFormulas(@Connector int connector, List<Formula> formulas) { + private static void validateFormulas( + @Connector int connector, List<IntegrityFormula> formulas) { switch (connector) { case AND: case OR: diff --git a/core/java/android/content/integrity/Formula.java b/core/java/android/content/integrity/Formula.java deleted file mode 100644 index b092a22c0191..000000000000 --- a/core/java/android/content/integrity/Formula.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.integrity; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.content.integrity.AtomicFormula.BooleanAtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; -import android.content.integrity.AtomicFormula.StringAtomicFormula; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Represents a rule logic/content. - * - * @hide - */ -@SystemApi -@VisibleForTesting -public interface Formula { - /** @hide */ - @IntDef( - value = { - COMPOUND_FORMULA_TAG, - STRING_ATOMIC_FORMULA_TAG, - INT_ATOMIC_FORMULA_TAG, - BOOLEAN_ATOMIC_FORMULA_TAG - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Tag {} - - int COMPOUND_FORMULA_TAG = 0; - int STRING_ATOMIC_FORMULA_TAG = 1; - int INT_ATOMIC_FORMULA_TAG = 2; - int BOOLEAN_ATOMIC_FORMULA_TAG = 3; - - /** - * Returns if this formula can be satisfied by substituting the corresponding information of - * {@code appInstallMetadata} into the formula. - */ - boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata); - - /** Returns the tag that identifies the current class. */ - @Tag int getTag(); - - /** - * Write a {@link Formula} to {@link android.os.Parcel}. - * - * <p>This helper method is needed because non-final class/interface are not allowed to be - * {@link Parcelable}. - * - * @throws IllegalArgumentException if {@link Formula} is not a recognized subclass - */ - static void writeToParcel(@NonNull Formula formula, @NonNull Parcel dest, int flags) { - dest.writeInt(formula.getTag()); - ((Parcelable) formula).writeToParcel(dest, flags); - } - - /** - * Read a {@link Formula} from a {@link android.os.Parcel}. - * - * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link - * Parcelable} (api lint error). - * - * @throws IllegalArgumentException if the parcel cannot be parsed - */ - @NonNull - static Formula readFromParcel(@NonNull Parcel in) { - int tag = in.readInt(); - switch (tag) { - case COMPOUND_FORMULA_TAG: - return CompoundFormula.CREATOR.createFromParcel(in); - case STRING_ATOMIC_FORMULA_TAG: - return StringAtomicFormula.CREATOR.createFromParcel(in); - case INT_ATOMIC_FORMULA_TAG: - return IntAtomicFormula.CREATOR.createFromParcel(in); - case BOOLEAN_ATOMIC_FORMULA_TAG: - return BooleanAtomicFormula.CREATOR.createFromParcel(in); - default: - throw new IllegalArgumentException("Unknown formula tag " + tag); - } - } -} diff --git a/core/java/android/content/integrity/IntegrityFormula.java b/core/java/android/content/integrity/IntegrityFormula.java new file mode 100644 index 000000000000..0660f93e9f01 --- /dev/null +++ b/core/java/android/content/integrity/IntegrityFormula.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.integrity; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.content.integrity.AtomicFormula.BooleanAtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; +import android.content.integrity.AtomicFormula.StringAtomicFormula; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * Represents a rule logic/content. + * + * @hide + */ +@SystemApi +@VisibleForTesting +public abstract class IntegrityFormula { + + /** + * A static formula base for package name formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula PACKAGE_NAME = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME); + + /** + * A static formula base for app certificate formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula APP_CERTIFICATE = + new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE); + + /** + * A static formula base for installer name formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula INSTALLER_NAME = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME); + + /** + * A static formula base for installer certificate formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula INSTALLER_CERTIFICATE = + new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE); + + /** + * A static formula base for version code name formulas. + * + * This formulation is incomplete and should always be used with {@code equals}, + * {@code greaterThan} and {@code greaterThanEquals} formulation. Evaluates to false when used + * directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula VERSION_CODE = + new LongAtomicFormula(AtomicFormula.VERSION_CODE); + + /** + * A static formula base for pre-installed status formulas. + * + * This formulation is incomplete and should always be used with {@code equals} formulation. + * Evaluates to false when used directly and cannot be written as a parcel. + */ + @NonNull + public static final IntegrityFormula PRE_INSTALLED = + new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED); + + /** @hide */ + @IntDef( + value = { + COMPOUND_FORMULA_TAG, + STRING_ATOMIC_FORMULA_TAG, + LONG_ATOMIC_FORMULA_TAG, + BOOLEAN_ATOMIC_FORMULA_TAG + }) + @Retention(RetentionPolicy.SOURCE) + @interface Tag {} + + /** @hide */ + public static final int COMPOUND_FORMULA_TAG = 0; + /** @hide */ + public static final int STRING_ATOMIC_FORMULA_TAG = 1; + /** @hide */ + public static final int LONG_ATOMIC_FORMULA_TAG = 2; + /** @hide */ + public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3; + + /** + * Returns the tag that identifies the current class. + * + * @hide + */ + public abstract @Tag int getTag(); + + /** + * Returns true when the integrity formula is satisfied by the {@code appInstallMetadata}. + * + * @hide + */ + public abstract @Tag boolean matches(AppInstallMetadata appInstallMetadata); + + /** + * Write an {@link IntegrityFormula} to {@link android.os.Parcel}. + * + * <p>This helper method is needed because non-final class/interface are not allowed to be + * {@link Parcelable}. + * + * @throws IllegalArgumentException if {@link IntegrityFormula} is not a recognized subclass + * + * @hide + */ + public static void writeToParcel( + @NonNull IntegrityFormula formula, @NonNull Parcel dest, int flags) { + dest.writeInt(formula.getTag()); + ((Parcelable) formula).writeToParcel(dest, flags); + } + + /** + * Read a {@link IntegrityFormula} from a {@link android.os.Parcel}. + * + * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link + * Parcelable} (api lint error). + * + * @throws IllegalArgumentException if the parcel cannot be parsed + * @hide + */ + @NonNull + public static IntegrityFormula readFromParcel(@NonNull Parcel in) { + int tag = in.readInt(); + switch (tag) { + case COMPOUND_FORMULA_TAG: + return CompoundFormula.CREATOR.createFromParcel(in); + case STRING_ATOMIC_FORMULA_TAG: + return StringAtomicFormula.CREATOR.createFromParcel(in); + case LONG_ATOMIC_FORMULA_TAG: + return LongAtomicFormula.CREATOR.createFromParcel(in); + case BOOLEAN_ATOMIC_FORMULA_TAG: + return BooleanAtomicFormula.CREATOR.createFromParcel(in); + default: + throw new IllegalArgumentException("Unknown formula tag " + tag); + } + } + + /** + * Returns an integrity formula that evaluates to true when value of the key matches to the + * provided string value. + * + * <p>The value will be hashed with SHA256 and the hex digest will be computed; for + * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value is less than + * 32 characters. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not string typed. + */ + @NonNull + public IntegrityFormula equalTo(@NonNull String value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.StringAtomicFormula(baseFormula.getKey(), value); + } + + /** + * Returns an integrity formula that evaluates to true when the boolean value of the key matches + * the provided boolean value. It can only be used with the boolean comparison keys. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not boolean typed. + */ + @NonNull + public IntegrityFormula equalTo(boolean value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.BooleanAtomicFormula(baseFormula.getKey(), value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is equal to {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula equalTo(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.EQ, value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is greater than {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula greaterThan(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GT, value); + } + + /** + * Returns a formula that evaluates to true when the value of the key in the package being + * installed is greater than or equals to the {@code value}. + * + * <p>Throws an {@link IllegalArgumentException} if the key is not long typed. + */ + @NonNull + public IntegrityFormula greaterThanOrEquals(long value) { + AtomicFormula baseFormula = (AtomicFormula) this; + return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GTE, value); + } + + /** + * Returns a formula that evaluates to true when any formula in {@code formulae} evaluates to + * true. + * + * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements. + */ + @NonNull + public static IntegrityFormula any(@NonNull IntegrityFormula... formulae) { + return new CompoundFormula(CompoundFormula.OR, Arrays.asList(formulae)); + } + + /** + * Returns a formula that evaluates to true when all formula in {@code formulae} evaluates to + * true. + * + * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements. + */ + @NonNull + public static IntegrityFormula all(@NonNull IntegrityFormula... formulae) { + return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae)); + } + + /** + * Returns a formula that evaluates to true when {@code formula} evaluates to false. + */ + @NonNull + public static IntegrityFormula not(@NonNull IntegrityFormula formula) { + return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula)); + } + + // Constructor is package private so it cannot be inherited outside of this package. + IntegrityFormula() { + } +} diff --git a/services/core/java/com/android/server/integrity/IntegrityUtils.java b/core/java/android/content/integrity/IntegrityUtils.java index f49c675dbd8d..c3f762469348 100644 --- a/services/core/java/com/android/server/integrity/IntegrityUtils.java +++ b/core/java/android/content/integrity/IntegrityUtils.java @@ -14,11 +14,15 @@ * limitations under the License. */ -package com.android.server.integrity; +package android.content.integrity; import static com.android.internal.util.Preconditions.checkArgument; -/** Utils class for simple operations used in integrity module. */ +/** + * Utils class for simple operations used in integrity module. + * + * @hide + */ public class IntegrityUtils { private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java index 77587851b18c..c421c4076d16 100644 --- a/core/java/android/content/integrity/Rule.java +++ b/core/java/android/content/integrity/Rule.java @@ -59,17 +59,17 @@ public final class Rule implements Parcelable { */ public static final int FORCE_ALLOW = 1; - private final @NonNull Formula mFormula; + private final @NonNull IntegrityFormula mFormula; private final @Effect int mEffect; - public Rule(@NonNull Formula formula, @Effect int effect) { + public Rule(@NonNull IntegrityFormula formula, @Effect int effect) { checkArgument(isValidEffect(effect), String.format("Unknown effect: %d", effect)); this.mFormula = Objects.requireNonNull(formula); this.mEffect = effect; } Rule(Parcel in) { - mFormula = Formula.readFromParcel(in); + mFormula = IntegrityFormula.readFromParcel(in); mEffect = in.readInt(); } @@ -94,12 +94,12 @@ public final class Rule implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - Formula.writeToParcel(mFormula, dest, flags); + IntegrityFormula.writeToParcel(mFormula, dest, flags); dest.writeInt(mEffect); } @NonNull - public Formula getFormula() { + public IntegrityFormula getFormula() { return mFormula; } @@ -141,7 +141,6 @@ public final class Rule implements Parcelable { } private static boolean isValidEffect(int effect) { - return effect == DENY - || effect == FORCE_ALLOW; + return effect == DENY || effect == FORCE_ALLOW; } } diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index a2f8886eb7d2..33d17763fb24 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -22,7 +22,11 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.content.Context; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -40,6 +44,10 @@ public class OverlayManager { private final IOverlayManager mService; private final Context mContext; + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long THROW_SECURITY_EXCEPTIONS = 147340954; + /** * Creates a new instance. * @@ -69,6 +77,9 @@ public class OverlayManager { * @param packageName the name of the overlay package to enable. * @param user The user for which to change the overlay. * + * @throws SecurityException when caller is not allowed to enable {@param packageName} + * @throws IllegalStateException when enabling fails otherwise + * * @hide */ @SystemApi @@ -77,11 +88,13 @@ public class OverlayManager { "android.permission.INTERACT_ACROSS_USERS_FULL" }) public void setEnabledExclusiveInCategory(@NonNull final String packageName, - @NonNull UserHandle user) { + @NonNull UserHandle user) throws SecurityException, IllegalStateException { try { if (!mService.setEnabledExclusiveInCategory(packageName, user.getIdentifier())) { throw new IllegalStateException("setEnabledExclusiveInCategory failed"); } + } catch (SecurityException e) { + rethrowSecurityException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -97,6 +110,9 @@ public class OverlayManager { * @param enable {@code false} if the overlay should be turned off. * @param user The user for which to change the overlay. * + * @throws SecurityException when caller is not allowed to enable/disable {@param packageName} + * @throws IllegalStateException when enabling/disabling fails otherwise + * * @hide */ @SystemApi @@ -105,15 +121,16 @@ public class OverlayManager { "android.permission.INTERACT_ACROSS_USERS_FULL" }) public void setEnabled(@NonNull final String packageName, final boolean enable, - @NonNull UserHandle user) { + @NonNull UserHandle user) throws SecurityException, IllegalStateException { try { if (!mService.setEnabled(packageName, enable, user.getIdentifier())) { throw new IllegalStateException("setEnabled failed"); } + } catch (SecurityException e) { + rethrowSecurityException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - return; } /** @@ -187,4 +204,29 @@ public class OverlayManager { throw e.rethrowFromSystemServer(); } } + + /** + * Starting on R, actor enforcement and app visibility changes introduce additional failure + * cases, but the SecurityException thrown with these checks is unexpected for existing + * consumers of the API. + * + * The only prior case it would be thrown is with a permission failure, but the calling + * application would be able to verify that themselves, and so they may choose to ignore + * catching SecurityException when calling these APIs. + * + * For R, this no longer holds true, and SecurityExceptions can be thrown for any number of + * reasons, none of which are exposed to the caller. So for consumers targeting below R, + * transform these SecurityExceptions into IllegalStateExceptions, which are a little more + * expected to be thrown by the setEnabled APIs. + * + * This will mask the prior permission exception if it applies, but it's assumed that apps + * wouldn't call the APIs without the permission on prior versions, and so it's safe to ignore. + */ + private void rethrowSecurityException(SecurityException e) { + if (!Compatibility.isChangeEnabled(THROW_SECURITY_EXCEPTIONS)) { + throw new IllegalStateException(e); + } else { + throw e; + } + } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 69a3c10c330b..b64c001ea6e2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2335,6 +2335,13 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device includes a hinge angle sensor. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports high fidelity sensor processing * capabilities. */ @@ -3536,6 +3543,44 @@ public abstract class PackageManager { public static final long FILTER_APPLICATION_QUERY = 135549675L; /** {@hide} */ + @IntDef(prefix = {"SYSTEM_APP_STATE_"}, value = { + SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN, + SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE, + SYSTEM_APP_STATE_INSTALLED, + SYSTEM_APP_STATE_UNINSTALLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SystemAppState {} + + /** + * Constant for noting system app state as hidden before installation + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; + + /** + * Constant for noting system app state as visible before installation + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; + + /** + * Constant for noting system app state as installed + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_INSTALLED = 2; + + /** + * Constant for noting system app state as not installed + * @hide + */ + @SystemApi + public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; + + /** {@hide} */ public int getUserId() { return UserHandle.myUserId(); } @@ -6639,6 +6684,17 @@ public abstract class PackageManager { @NonNull UserHandle userHandle); /** + * Sets system app state + * @param packageName Package name of the app. + * @param state State of the app. + * @hide + */ + @SystemApi + public void setSystemAppState(@NonNull String packageName, @SystemAppState int state) { + throw new RuntimeException("Not implemented. Must override in a subclass"); + } + + /** * Return whether the device has been booted into safe mode. */ public abstract boolean isSafeMode(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index fd4c26569873..dbfc65066c11 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -41,6 +41,7 @@ import static android.os.Build.VERSION_CODES.O; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; +import android.annotation.AnyThread; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -1080,6 +1081,7 @@ public class PackageParser { * * @see #parsePackage(File, int, boolean) */ + @AnyThread public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches) throws PackageParserException { ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null; diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java index 73b75df80e5b..851a08116f56 100644 --- a/core/java/android/content/pm/SuspendDialogInfo.java +++ b/core/java/android/content/pm/SuspendDialogInfo.java @@ -19,6 +19,7 @@ package android.content.pm; import static android.content.res.Resources.ID_NULL; import android.annotation.DrawableRes; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; @@ -36,20 +37,21 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Locale; import java.util.Objects; /** * A container to describe the dialog to be shown when the user tries to launch a suspended - * application. - * The suspending app can customize the dialog's following attributes: + * application. The suspending app can customize the dialog's following attributes: * <ul> * <li>The dialog icon, by providing a resource id. * <li>The title text, by providing a resource id. * <li>The text of the dialog's body, by providing a resource id or a string. - * <li>The text on the neutral button which starts the - * {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS SHOW_SUSPENDED_APP_DETAILS} - * activity, by providing a resource id. + * <li>The text on the neutral button by providing a resource id. + * <li>The action performed on tapping the neutral button. Only {@link #BUTTON_ACTION_UNSUSPEND} + * and {@link #BUTTON_ACTION_MORE_DETAILS} are currently supported. * </ul> * System defaults are used whenever any of these are not provided, or any of the provided resource * ids cannot be resolved at the time of displaying the dialog. @@ -67,12 +69,47 @@ public final class SuspendDialogInfo implements Parcelable { private static final String XML_ATTR_DIALOG_MESSAGE_RES_ID = "dialogMessageResId"; private static final String XML_ATTR_DIALOG_MESSAGE = "dialogMessage"; private static final String XML_ATTR_BUTTON_TEXT_RES_ID = "buttonTextResId"; + private static final String XML_ATTR_BUTTON_ACTION = "buttonAction"; private final int mIconResId; private final int mTitleResId; private final int mDialogMessageResId; private final String mDialogMessage; private final int mNeutralButtonTextResId; + private final int mNeutralButtonAction; + + /** + * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that + * starts the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. + * @see Builder#setNeutralButtonAction(int) + */ + public static final int BUTTON_ACTION_MORE_DETAILS = 0; + + /** + * Used with {@link Builder#setNeutralButtonAction(int)} to create a neutral button that + * unsuspends the app that the user was trying to launch and continues with the launch. The + * system also sends the broadcast + * {@link android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY} to the suspending app + * when this happens. + * @see Builder#setNeutralButtonAction(int) + * @see android.content.Intent#ACTION_PACKAGE_UNSUSPENDED_MANUALLY + */ + public static final int BUTTON_ACTION_UNSUSPEND = 1; + + /** + * Button actions to specify what happens when the user taps on the neutral button. + * To be used with {@link Builder#setNeutralButtonAction(int)}. + * + * @hide + * @see Builder#setNeutralButtonAction(int) + */ + @IntDef(flag = true, prefix = {"BUTTON_ACTION_"}, value = { + BUTTON_ACTION_MORE_DETAILS, + BUTTON_ACTION_UNSUSPEND + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ButtonAction { + } /** * @return the resource id of the icon to be used with the dialog @@ -102,8 +139,8 @@ public final class SuspendDialogInfo implements Parcelable { } /** - * @return the text to be shown in the dialog's body. Returns {@code null} if - * {@link #getDialogMessageResId()} returns a valid resource id. + * @return the text to be shown in the dialog's body. Returns {@code null} if {@link + * #getDialogMessageResId()} returns a valid resource id * @hide */ @Nullable @@ -121,6 +158,15 @@ public final class SuspendDialogInfo implements Parcelable { } /** + * @return The {@link ButtonAction} that happens on tapping this button + * @hide + */ + @ButtonAction + public int getNeutralButtonAction() { + return mNeutralButtonAction; + } + + /** * @hide */ public void saveToXml(XmlSerializer out) throws IOException { @@ -138,6 +184,7 @@ public final class SuspendDialogInfo implements Parcelable { if (mNeutralButtonTextResId != ID_NULL) { XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId); } + XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction); } /** @@ -150,6 +197,8 @@ public final class SuspendDialogInfo implements Parcelable { final int titleId = XmlUtils.readIntAttribute(in, XML_ATTR_TITLE_RES_ID, ID_NULL); final int buttonTextId = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_TEXT_RES_ID, ID_NULL); + final int buttonAction = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_ACTION, + BUTTON_ACTION_MORE_DETAILS); final int dialogMessageResId = XmlUtils.readIntAttribute( in, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL); final String dialogMessage = XmlUtils.readStringAttribute(in, XML_ATTR_DIALOG_MESSAGE); @@ -168,6 +217,7 @@ public final class SuspendDialogInfo implements Parcelable { } else if (dialogMessage != null) { dialogInfoBuilder.setMessage(dialogMessage); } + dialogInfoBuilder.setNeutralButtonAction(buttonAction); } catch (Exception e) { Slog.e(TAG, "Exception while parsing from xml. Some fields may default", e); } @@ -181,6 +231,7 @@ public final class SuspendDialogInfo implements Parcelable { hashCode = 31 * hashCode + mNeutralButtonTextResId; hashCode = 31 * hashCode + mDialogMessageResId; hashCode = 31 * hashCode + Objects.hashCode(mDialogMessage); + hashCode = 31 * hashCode + mNeutralButtonAction; return hashCode; } @@ -197,6 +248,7 @@ public final class SuspendDialogInfo implements Parcelable { && mTitleResId == otherDialogInfo.mTitleResId && mDialogMessageResId == otherDialogInfo.mDialogMessageResId && mNeutralButtonTextResId == otherDialogInfo.mNeutralButtonTextResId + && mNeutralButtonAction == otherDialogInfo.mNeutralButtonAction && Objects.equals(mDialogMessage, otherDialogInfo.mDialogMessage); } @@ -228,6 +280,8 @@ public final class SuspendDialogInfo implements Parcelable { builder.append(mDialogMessage); builder.append("\" "); } + builder.append("mNeutralButtonAction = "); + builder.append(mNeutralButtonAction); builder.append("}"); return builder.toString(); } @@ -244,6 +298,7 @@ public final class SuspendDialogInfo implements Parcelable { dest.writeInt(mDialogMessageResId); dest.writeString(mDialogMessage); dest.writeInt(mNeutralButtonTextResId); + dest.writeInt(mNeutralButtonAction); } private SuspendDialogInfo(Parcel source) { @@ -252,6 +307,7 @@ public final class SuspendDialogInfo implements Parcelable { mDialogMessageResId = source.readInt(); mDialogMessage = source.readString(); mNeutralButtonTextResId = source.readInt(); + mNeutralButtonAction = source.readInt(); } SuspendDialogInfo(Builder b) { @@ -260,9 +316,11 @@ public final class SuspendDialogInfo implements Parcelable { mDialogMessageResId = b.mDialogMessageResId; mDialogMessage = (mDialogMessageResId == ID_NULL) ? b.mDialogMessage : null; mNeutralButtonTextResId = b.mNeutralButtonTextResId; + mNeutralButtonAction = b.mNeutralButtonAction; } - public static final @android.annotation.NonNull Creator<SuspendDialogInfo> CREATOR = new Creator<SuspendDialogInfo>() { + public static final @NonNull Creator<SuspendDialogInfo> CREATOR = + new Creator<SuspendDialogInfo>() { @Override public SuspendDialogInfo createFromParcel(Parcel source) { return new SuspendDialogInfo(source); @@ -283,6 +341,7 @@ public final class SuspendDialogInfo implements Parcelable { private int mTitleResId = ID_NULL; private int mIconResId = ID_NULL; private int mNeutralButtonTextResId = ID_NULL; + private int mNeutralButtonAction = BUTTON_ACTION_MORE_DETAILS; /** * Set the resource id of the icon to be used. If not provided, no icon will be shown. @@ -333,8 +392,8 @@ public final class SuspendDialogInfo implements Parcelable { /** * Set the resource id of the dialog message to be shown. If no dialog message is provided - * via either this method or {@link #setMessage(String)}, the system will use a - * default message. + * via either this method or {@link #setMessage(String)}, the system will use a default + * message. * <p> * The system will use {@link android.content.res.Resources#getString(int, Object...) * getString} to insert the suspended app name into the message, so an example format string @@ -353,9 +412,10 @@ public final class SuspendDialogInfo implements Parcelable { } /** - * Set the resource id of text to be shown on the neutral button. Tapping this button starts - * the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. If this is - * not provided, the system will use a default text. + * Set the resource id of text to be shown on the neutral button. Tapping this button would + * perform the {@link ButtonAction action} specified through + * {@link #setNeutralButtonAction(int)}. If this is not provided, the system will use a + * default text. * * @param resId The resource id of the button text * @return this builder object. @@ -368,6 +428,22 @@ public final class SuspendDialogInfo implements Parcelable { } /** + * Set the action expected to happen on neutral button tap. Defaults to + * {@link #BUTTON_ACTION_MORE_DETAILS} if this is not provided. + * + * @param buttonAction Either {@link #BUTTON_ACTION_MORE_DETAILS} or + * {@link #BUTTON_ACTION_UNSUSPEND}. + * @return this builder object + */ + @NonNull + public Builder setNeutralButtonAction(@ButtonAction int buttonAction) { + Preconditions.checkArgument(buttonAction == BUTTON_ACTION_MORE_DETAILS + || buttonAction == BUTTON_ACTION_UNSUSPEND, "Invalid button action"); + mNeutralButtonAction = buttonAction; + return this; + } + + /** * Build the final object based on given inputs. * * @return The {@link SuspendDialogInfo} object built using this builder. diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java index 13122d249b23..6412a0ce7219 100644 --- a/core/java/android/hardware/display/BrightnessConfiguration.java +++ b/core/java/android/hardware/display/BrightnessConfiguration.java @@ -61,7 +61,7 @@ public final class BrightnessConfiguration implements Parcelable { private static final String ATTR_MODEL_LOWER_BOUND = "model-lower-bound"; private static final String ATTR_MODEL_UPPER_BOUND = "model-upper-bound"; /** - * Returned from {@link #getShortTermModelTimeout()} if no timeout has been set. + * Returned from {@link #getShortTermModelTimeoutMillis()} if no timeout has been set. * In this case the device will use the default timeout available in the * {@link BrightnessConfiguration} returned from * {@link DisplayManager#getDefaultBrightnessConfiguration()}. @@ -160,7 +160,7 @@ public final class BrightnessConfiguration implements Parcelable { * {@link #getShortTermModelUpperLuxMultiplier()} to decide whether to keep any adjustment * the user has made to adaptive brightness. */ - public long getShortTermModelTimeout() { + public long getShortTermModelTimeoutMillis() { return mShortTermModelTimeout; } @@ -326,7 +326,7 @@ public final class BrightnessConfiguration implements Parcelable { builder.setDescription(description); final boolean shouldCollectColorSamples = in.readBoolean(); builder.setShouldCollectColorSamples(shouldCollectColorSamples); - builder.setShortTermModelTimeout(in.readLong()); + builder.setShortTermModelTimeoutMillis(in.readLong()); builder.setShortTermModelLowerLuxMultiplier(in.readFloat()); builder.setShortTermModelUpperLuxMultiplier(in.readFloat()); return builder.build(); @@ -487,7 +487,7 @@ public final class BrightnessConfiguration implements Parcelable { builder.addCorrectionByCategory(category, correction); } builder.setShouldCollectColorSamples(shouldCollectColorSamples); - builder.setShortTermModelTimeout(shortTermModelTimeout); + builder.setShortTermModelTimeoutMillis(shortTermModelTimeout); builder.setShortTermModelLowerLuxMultiplier(shortTermModelLowerLuxMultiplier); builder.setShortTermModelUpperLuxMultiplier(shortTermModelUpperLuxMultiplier); return builder.build(); @@ -673,8 +673,8 @@ public final class BrightnessConfiguration implements Parcelable { * adjustment the user has made to adaptive brightness. */ @NonNull - public Builder setShortTermModelTimeout(long shortTermModelTimeout) { - mShortTermModelTimeout = shortTermModelTimeout; + public Builder setShortTermModelTimeoutMillis(long shortTermModelTimeoutMillis) { + mShortTermModelTimeout = shortTermModelTimeoutMillis; return this; } diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java index c6a5dd0d048d..43480ab9cc44 100644 --- a/core/java/android/hardware/location/ContextHubClient.java +++ b/core/java/android/hardware/location/ContextHubClient.java @@ -136,7 +136,10 @@ public class ContextHubClient implements Closeable { * @see NanoAppMessage * @see ContextHubTransaction.Result */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @ContextHubTransaction.Result public int sendMessageToNanoApp(@NonNull NanoAppMessage message) { Objects.requireNonNull(message, "NanoAppMessage cannot be null"); diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index a51d2c929a2c..1001f800df3c 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -44,7 +44,9 @@ import java.util.concurrent.Executor; * A class that exposes the Context hubs on a device to applications. * * Please note that this class is not expected to be used by unbundled applications. Also, calling - * applications are expected to have LOCATION_HARDWARE permissions to use this class. + * applications are expected to have LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permissions to use this + * class. Use of LOCATION_HARDWARE to enable access to these APIs is deprecated and may be removed + * in the future - all applications are recommended to move to the ACCESS_CONTEXT_HUB permission. * * @hide */ @@ -196,7 +198,10 @@ public final class ContextHubManager { * new APIs. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) public int[] getContextHubHandles() { try { return mService.getContextHubHandles(); @@ -217,7 +222,10 @@ public final class ContextHubManager { * new APIs. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) public ContextHubInfo getContextHubInfo(int hubHandle) { try { return mService.getContextHubInfo(hubHandle); @@ -248,7 +256,10 @@ public final class ContextHubManager { * @deprecated Use {@link #loadNanoApp(ContextHubInfo, NanoAppBinary)} instead. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) public int loadNanoApp(int hubHandle, @NonNull NanoApp app) { try { return mService.loadNanoApp(hubHandle, app); @@ -275,7 +286,10 @@ public final class ContextHubManager { * @deprecated Use {@link #unloadNanoApp(ContextHubInfo, long)} instead. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) public int unloadNanoApp(int nanoAppHandle) { try { return mService.unloadNanoApp(nanoAppHandle); @@ -315,7 +329,10 @@ public final class ContextHubManager { * for loaded nanoapps. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @Nullable public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) { try { return mService.getNanoAppInstanceInfo(nanoAppHandle); @@ -338,7 +355,10 @@ public final class ContextHubManager { * for loaded nanoapps. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public int[] findNanoAppOnHub(int hubHandle, @NonNull NanoAppFilter filter) { try { return mService.findNanoAppOnHub(hubHandle, filter); @@ -373,7 +393,10 @@ public final class ContextHubManager { * or {@link #createClient(ContextHubInfo, ContextHubClientCallback)}. */ @Deprecated - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) public int sendMessage(int hubHandle, int nanoAppHandle, @NonNull ContextHubMessage message) { try { return mService.sendMessage(hubHandle, nanoAppHandle, message); @@ -389,7 +412,10 @@ public final class ContextHubManager { * * @see ContextHubInfo */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public List<ContextHubInfo> getContextHubs() { try { return mService.getContextHubs(); @@ -466,7 +492,10 @@ public final class ContextHubManager { * * @see NanoAppBinary */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubTransaction<Void> loadNanoApp( @NonNull ContextHubInfo hubInfo, @NonNull NanoAppBinary appBinary) { Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null"); @@ -495,7 +524,10 @@ public final class ContextHubManager { * * @throws NullPointerException if hubInfo is null */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubTransaction<Void> unloadNanoApp( @NonNull ContextHubInfo hubInfo, long nanoAppId) { Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null"); @@ -523,7 +555,10 @@ public final class ContextHubManager { * * @throws NullPointerException if hubInfo is null */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubTransaction<Void> enableNanoApp( @NonNull ContextHubInfo hubInfo, long nanoAppId) { Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null"); @@ -551,7 +586,10 @@ public final class ContextHubManager { * * @throws NullPointerException if hubInfo is null */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubTransaction<Void> disableNanoApp( @NonNull ContextHubInfo hubInfo, long nanoAppId) { Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null"); @@ -578,7 +616,10 @@ public final class ContextHubManager { * * @throws NullPointerException if hubInfo is null */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubTransaction<List<NanoAppState>> queryNanoApps( @NonNull ContextHubInfo hubInfo) { Objects.requireNonNull(hubInfo, "ContextHubInfo cannot be null"); @@ -724,7 +765,10 @@ public final class ContextHubManager { * * @see ContextHubClientCallback */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubClient createClient( @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback, @NonNull @CallbackExecutor Executor executor) { @@ -761,7 +805,10 @@ public final class ContextHubManager { * * @see ContextHubClientCallback */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubClient createClient( @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) { return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain())); @@ -780,6 +827,9 @@ public final class ContextHubManager { * If a client is regenerated, the host endpoint identifier attached to messages sent to the * nanoapp remains consistent, even if the original process has exited. * + * To avoid unintentionally spreading data from the Context Hub to external applications, it is + * strongly recommended that the PendingIntent supplied to this API is an explicit intent. + * * If registered successfully, intents will be delivered regarding events or messages from the * specified nanoapp from the attached Context Hub. The intent will have an extra * {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which @@ -804,7 +854,10 @@ public final class ContextHubManager { * @throws IllegalStateException if there were too many registered clients at the service * @throws NullPointerException if pendingIntent or hubInfo is null */ - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + @RequiresPermission(anyOf = { + android.Manifest.permission.LOCATION_HARDWARE, + android.Manifest.permission.ACCESS_CONTEXT_HUB + }) @NonNull public ContextHubClient createClient( @NonNull ContextHubInfo hubInfo, @NonNull PendingIntent pendingIntent, long nanoAppId) { Objects.requireNonNull(pendingIntent); diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index fd015b4fe52c..a3899b705c1b 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,7 +16,10 @@ package android.net; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; @@ -24,12 +27,15 @@ import android.os.Message; import android.os.RemoteException; import java.util.ArrayList; +import java.util.Objects; /** * A class representing the IP configuration of the Ethernet network. * * @hide */ +@SystemApi +@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; @@ -37,7 +43,7 @@ public class EthernetManager { private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MSG_AVAILABILITY_CHANGED) { @@ -60,12 +66,14 @@ public class EthernetManager { /** * A listener interface to receive notification on changes in Ethernet. + * @hide */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. + * @hide */ @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); @@ -76,6 +84,7 @@ public class EthernetManager { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. + * @hide */ public EthernetManager(Context context, IEthernetManager service) { mContext = context; @@ -85,6 +94,7 @@ public class EthernetManager { /** * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + * @hide */ @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { @@ -97,6 +107,7 @@ public class EthernetManager { /** * Set Ethernet configuration. + * @hide */ @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { @@ -109,6 +120,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. + * @hide */ @UnsupportedAppUsage public boolean isAvailable() { @@ -119,6 +131,7 @@ public class EthernetManager { * Indicates whether the system has given interface. * * @param iface Ethernet interface name + * @hide */ @UnsupportedAppUsage public boolean isAvailable(String iface) { @@ -133,6 +146,7 @@ public class EthernetManager { * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void addListener(Listener listener) { @@ -151,6 +165,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. + * @hide */ @UnsupportedAppUsage public String[] getAvailableInterfaces() { @@ -165,6 +180,7 @@ public class EthernetManager { * Removes a listener. * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void removeListener(Listener listener) { @@ -180,4 +196,78 @@ public class EthernetManager { } } } + + /** + * A request for a tethered interface. + */ + public static class TetheredInterfaceRequest { + private final IEthernetManager mService; + private final ITetheredInterfaceCallback mCb; + + private TetheredInterfaceRequest(@NonNull IEthernetManager service, + @NonNull ITetheredInterfaceCallback cb) { + this.mService = service; + this.mCb = cb; + } + + /** + * Release the request, causing the interface to revert back from tethering mode if there + * is no other requestor. + */ + public void release() { + try { + mService.releaseTetheredInterface(mCb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + /** + * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. + */ + public interface TetheredInterfaceCallback { + /** + * Called when the tethered interface is available. + * @param iface The name of the interface. + */ + void onAvailable(@NonNull String iface); + + /** + * Called when the tethered interface is now unavailable. + */ + void onUnavailable(); + } + + /** + * Request a tethered interface in tethering mode. + * + * <p>When this method is called and there is at least one ethernet interface available, the + * system will designate one to act as a tethered interface. If there is already a tethered + * interface, the existing interface will be used. + * @param callback A callback to be called once the request has been fulfilled. + */ + @NonNull + public TetheredInterfaceRequest requestTetheredInterface( + @NonNull TetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "Callback must be non-null"); + final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { + @Override + public void onAvailable(String iface) { + callback.onAvailable(iface); + } + + @Override + public void onUnavailable() { + callback.onUnavailable(); + } + }; + + try { + mService.requestTetheredInterface(cbInternal); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return new TetheredInterfaceRequest(mService, cbInternal); + } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 94960b51d329..ccc6e352098f 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; /** * Interface that answers queries about, and allows changing @@ -32,4 +33,6 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void requestTetheredInterface(in ITetheredInterfaceCallback callback); + void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl index 0beaaab4f639..e3d075988c8a 100644 --- a/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.aidl +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -1,12 +1,11 @@ /* - * - * Copyright 2019, The Android Open Source Project + * 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 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,6 +14,10 @@ * limitations under the License. */ -package android.telephony.ims; +package android.net; -parcelable RcsEventQueryResultDescriptor; +/** @hide */ +interface ITetheredInterfaceCallback { + void onAvailable(in String iface); + void onUnavailable(); +}
\ No newline at end of file diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 8d9f0d068a57..a9d7f17017c4 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -102,9 +102,9 @@ public class LinkAddress implements Parcelable { /** * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be - * or was deprecated. {@link #LIFETIME_UNKNOWN} indicates this information is not available. At - * the time existing connections can still use this address until it expires, but new - * connections should use the new address. {@link #LIFETIME_PERMANENT} indicates this + * or was deprecated. At the time existing connections can still use this address until it + * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates + * this information is not available. {@link #LIFETIME_PERMANENT} indicates this * {@link LinkAddress} will never be deprecated. */ private long deprecationTime; @@ -261,10 +261,10 @@ public class LinkAddress implements Parcelable { * @param scope An integer defining the scope in which the address is unique (e.g., * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when - * this {@link LinkAddress} will be or was deprecated. - * {@link #LIFETIME_UNKNOWN} indicates this information is not available. - * At the time existing connections can still use this address until it - * expires, but new connections should use the new address. + * this {@link LinkAddress} will be or was deprecated. At the time + * existing connections can still use this address until it expires, but + * new connections should use the new address. {@link #LIFETIME_UNKNOWN} + * indicates this information is not available. * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will * never be deprecated. * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this @@ -441,7 +441,7 @@ public class LinkAddress implements Parcelable { if (expirationTime == LIFETIME_PERMANENT) { flags |= IFA_F_PERMANENT; } else if (expirationTime != LIFETIME_UNKNOWN) { - // If we know this address expired or will expire in the future or, then this address + // If we know this address expired or will expire in the future, then this address // should not be permanent. flags &= ~IFA_F_PERMANENT; } @@ -458,10 +458,13 @@ public class LinkAddress implements Parcelable { } /** - * @return The time that this address will be deprecated. At the time the existing connection - * can still use this address until it expires, but the new connection should use the new - * address. This is the EPOCH time in milliseconds. 0 indicates this information is not - * available. + * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this + * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use + * this address until it expires, but new connections should use the new address. + * + * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this + * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} + * will never be deprecated. * * @hide */ @@ -472,8 +475,12 @@ public class LinkAddress implements Parcelable { } /** - * @return The time that this address will expire and will be no longer valid. This is the EPOCH - * time in milliseconds. 0 indicates this information is not available. + * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this + * {@link LinkAddress} will expire and be removed from the interface. + * + * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this + * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} + * will never expire. * * @hide */ diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index a94109dae7d5..4f4e27b446ef 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -26,6 +26,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -58,7 +59,6 @@ import java.util.StringJoiner; */ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; - private static final int INVALID_UID = -1; // Set to true when private DNS is broken. private boolean mPrivateDnsBroken; @@ -85,8 +85,8 @@ public final class NetworkCapabilities implements Parcelable { mTransportInfo = null; mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; mUids = null; - mEstablishingVpnAppUid = INVALID_UID; mAdministratorUids.clear(); + mOwnerUid = Process.INVALID_UID; mSSID = null; mPrivateDnsBroken = false; } @@ -104,8 +104,8 @@ public final class NetworkCapabilities implements Parcelable { mTransportInfo = nc.mTransportInfo; mSignalStrength = nc.mSignalStrength; setUids(nc.mUids); // Will make the defensive copy - mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid; setAdministratorUids(nc.mAdministratorUids); + mOwnerUid = nc.mOwnerUid; mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; mSSID = nc.mSSID; mPrivateDnsBroken = nc.mPrivateDnsBroken; @@ -810,31 +810,26 @@ public final class NetworkCapabilities implements Parcelable { } /** - * UID of the app that manages this network, or INVALID_UID if none/unknown. + * UID of the app that owns this network, or INVALID_UID if none/unknown. * - * This field keeps track of the UID of the app that created this network and is in charge - * of managing it. In the practice, it is used to store the UID of VPN apps so it is named - * accordingly, but it may be renamed if other mechanisms are offered for third party apps - * to create networks. - * - * Because this field is only used in the services side (and to avoid apps being able to - * set this to whatever they want), this field is not parcelled and will not be conserved - * across the IPC boundary. - * @hide + * <p>This field keeps track of the UID of the app that created this network and is in charge of + * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running + * VPN, or Carrier Service app managing a cellular data connection. */ - private int mEstablishingVpnAppUid = INVALID_UID; + private int mOwnerUid = Process.INVALID_UID; /** - * Set the UID of the managing app. - * @hide + * Set the UID of the owner app. */ - public void setEstablishingVpnAppUid(final int uid) { - mEstablishingVpnAppUid = uid; + public void setOwnerUid(final int uid) { + mOwnerUid = uid; } - /** @hide */ - public int getEstablishingVpnAppUid() { - return mEstablishingVpnAppUid; + /** + * Retrieves the UID of the owner app. + */ + public int getOwnerUid() { + return mOwnerUid; } /** @@ -1157,7 +1152,7 @@ public final class NetworkCapabilities implements Parcelable { * member is null, then the network is not restricted by app UID. If it's an empty list, then * it means nobody can use it. * As a special exception, the app managing this network (as identified by its UID stored in - * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in + * mOwnerUid) can always see this network. This is embodied by a special check in * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong> * to the app that manages it as determined by #appliesToUid. * <p> @@ -1264,7 +1259,7 @@ public final class NetworkCapabilities implements Parcelable { * in the passed nc (representing the UIDs that this network is available to). * <p> * As a special exception, the UID that created the passed network (as represented by its - * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN + * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app * can see its own network when it listens for it. * <p> @@ -1275,7 +1270,7 @@ public final class NetworkCapabilities implements Parcelable { public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) { if (null == nc.mUids || null == mUids) return true; // The network satisfies everything. for (UidRange requiredRange : mUids) { - if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true; + if (requiredRange.contains(nc.mOwnerUid)) return true; if (!nc.appliesToUidRange(requiredRange)) { return false; } @@ -1541,6 +1536,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeString(mSSID); dest.writeBoolean(mPrivateDnsBroken); dest.writeList(mAdministratorUids); + dest.writeInt(mOwnerUid); } public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR = @@ -1562,6 +1558,7 @@ public final class NetworkCapabilities implements Parcelable { netCap.mSSID = in.readString(); netCap.mPrivateDnsBroken = in.readBoolean(); netCap.setAdministratorUids(in.readArrayList(null)); + netCap.mOwnerUid = in.readInt(); return netCap; } @Override @@ -1611,8 +1608,8 @@ public final class NetworkCapabilities implements Parcelable { sb.append(" Uids: <").append(mUids).append(">"); } } - if (mEstablishingVpnAppUid != INVALID_UID) { - sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid); + if (mOwnerUid != Process.INVALID_UID) { + sb.append(" OwnerUid: ").append(mOwnerUid); } if (!mAdministratorUids.isEmpty()) { diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java index 4469d7de28fb..5cd4eb576aad 100644 --- a/core/java/android/net/NetworkKey.java +++ b/core/java/android/net/NetworkKey.java @@ -75,13 +75,11 @@ public class NetworkKey implements Parcelable { * * @return A new {@link NetworkKey} instance or <code>null</code> if the given * {@link ScanResult} instance is malformed. - * @throws IllegalArgumentException + * @throws NullPointerException */ @Nullable public static NetworkKey createFromScanResult(@NonNull ScanResult result) { - if (result == null) { - throw new IllegalArgumentException("ScanResult cannot be null"); - } + Objects.requireNonNull(result); final String ssid = result.SSID; if (TextUtils.isEmpty(ssid) || ssid.equals(WifiManager.UNKNOWN_SSID)) { return null; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index c7a8474c8038..8daf6e8cc1e9 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -179,6 +179,12 @@ public class Process { public static final int OTA_UPDATE_UID = 1061; /** + * Defines the UID used for statsd + * @hide + */ + public static final int STATSD_UID = 1066; + + /** * Defines the UID used for incidentd. * @hide */ @@ -856,6 +862,17 @@ public class Process { throws IllegalArgumentException, SecurityException; /** + * Freeze or unfreeze the specified process. + * + * @param pid Identifier of the process to freeze or unfreeze. + * @param uid Identifier of the user the process is running under. + * @param frozen Specify whether to free (true) or unfreeze (false). + * + * @hide + */ + public static final native void setProcessFrozen(int pid, int uid, boolean frozen); + + /** * Return the scheduling group of requested process. * * @hide diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java deleted file mode 100644 index 320fc137b8fa..000000000000 --- a/core/java/android/os/StatsLogEventWrapper.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.os; - -import android.util.Slog; - -import java.util.ArrayList; -import java.util.List; - -/** - * Wrapper class for sending data from Android OS to StatsD. - * - * @hide - */ -public final class StatsLogEventWrapper implements Parcelable { - static final boolean DEBUG = false; - static final String TAG = "StatsLogEventWrapper"; - - // Keep in sync with FieldValue.h enums - private static final int EVENT_TYPE_UNKNOWN = 0; - private static final int EVENT_TYPE_INT = 1; /* int32_t */ - private static final int EVENT_TYPE_LONG = 2; /* int64_t */ - private static final int EVENT_TYPE_FLOAT = 3; - private static final int EVENT_TYPE_DOUBLE = 4; - private static final int EVENT_TYPE_STRING = 5; - private static final int EVENT_TYPE_STORAGE = 6; - - List<Integer> mTypes = new ArrayList<>(); - List<Object> mValues = new ArrayList<>(); - int mTag; - long mElapsedTimeNs; - long mWallClockTimeNs; - WorkSource mWorkSource = null; - - public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) { - this.mTag = tag; - this.mElapsedTimeNs = elapsedTimeNs; - this.mWallClockTimeNs = wallClockTimeNs; - } - - /** - * Boilerplate for Parcel. - */ - public static final @android.annotation.NonNull Parcelable.Creator<StatsLogEventWrapper> CREATOR = new - Parcelable.Creator<StatsLogEventWrapper>() { - public StatsLogEventWrapper createFromParcel(Parcel in) { - return new StatsLogEventWrapper(in); - } - - public StatsLogEventWrapper[] newArray(int size) { - return new StatsLogEventWrapper[size]; - } - }; - - private StatsLogEventWrapper(Parcel in) { - readFromParcel(in); - } - - /** - * Set work source if any. - */ - public void setWorkSource(WorkSource ws) { - if (ws.getWorkChains() == null || ws.getWorkChains().size() == 0) { - Slog.w(TAG, "Empty worksource!"); - return; - } - mWorkSource = ws; - } - - /** - * Write a int value. - */ - public void writeInt(int val) { - mTypes.add(EVENT_TYPE_INT); - mValues.add(val); - } - - /** - * Write a long value. - */ - public void writeLong(long val) { - mTypes.add(EVENT_TYPE_LONG); - mValues.add(val); - } - - /** - * Write a string value. - */ - public void writeString(String val) { - mTypes.add(EVENT_TYPE_STRING); - // use empty string for null - mValues.add(val == null ? "" : val); - } - - /** - * Write a float value. - */ - public void writeFloat(float val) { - mTypes.add(EVENT_TYPE_FLOAT); - mValues.add(val); - } - - /** - * Write a storage value. - */ - public void writeStorage(byte[] val) { - mTypes.add(EVENT_TYPE_STORAGE); - mValues.add(val); - } - - /** - * Write a boolean value. - */ - public void writeBoolean(boolean val) { - mTypes.add(EVENT_TYPE_INT); - mValues.add(val ? 1 : 0); - } - - public void writeToParcel(Parcel out, int flags) { - if (DEBUG) { - Slog.d(TAG, - "Writing " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs + " and " - + mTypes.size() + " elements."); - } - out.writeInt(mTag); - out.writeLong(mElapsedTimeNs); - out.writeLong(mWallClockTimeNs); - if (mWorkSource != null) { - List<WorkSource.WorkChain> workChains = mWorkSource.getWorkChains(); - // number of chains - out.writeInt(workChains.size()); - for (int i = 0; i < workChains.size(); i++) { - android.os.WorkSource.WorkChain wc = workChains.get(i); - if (wc.getSize() == 0) { - Slog.w(TAG, "Empty work chain."); - out.writeInt(0); - continue; - } - if (wc.getUids().length != wc.getTags().length - || wc.getUids().length != wc.getSize()) { - Slog.w(TAG, "Malformated work chain."); - out.writeInt(0); - continue; - } - // number of nodes - out.writeInt(wc.getSize()); - for (int j = 0; j < wc.getSize(); j++) { - out.writeInt(wc.getUids()[j]); - out.writeString(wc.getTags()[j] == null ? "" : wc.getTags()[j]); - } - } - } else { - // no chains - out.writeInt(0); - } - out.writeInt(mTypes.size()); - for (int i = 0; i < mTypes.size(); i++) { - out.writeInt(mTypes.get(i)); - switch (mTypes.get(i)) { - case EVENT_TYPE_INT: - out.writeInt((int) mValues.get(i)); - break; - case EVENT_TYPE_LONG: - out.writeLong((long) mValues.get(i)); - break; - case EVENT_TYPE_FLOAT: - out.writeFloat((float) mValues.get(i)); - break; - case EVENT_TYPE_DOUBLE: - out.writeDouble((double) mValues.get(i)); - break; - case EVENT_TYPE_STRING: - out.writeString((String) mValues.get(i)); - break; - case EVENT_TYPE_STORAGE: - out.writeByteArray((byte[]) mValues.get(i)); - break; - default: - break; - } - } - } - - /** - * Reads from parcel and appropriately fills member fields. - */ - public void readFromParcel(Parcel in) { - mTypes = new ArrayList<>(); - mValues = new ArrayList<>(); - mWorkSource = null; - - mTag = in.readInt(); - mElapsedTimeNs = in.readLong(); - mWallClockTimeNs = in.readLong(); - - // Clear any data. - if (DEBUG) { - Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs); - } - // Set up worksource if present. - int numWorkChains = in.readInt(); - if (numWorkChains > 0) { - mWorkSource = new WorkSource(); - for (int i = 0; i < numWorkChains; i++) { - android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain(); - int workChainSize = in.readInt(); - for (int j = 0; j < workChainSize; j++) { - int uid = in.readInt(); - String tag = in.readString(); - workChain.addNode(uid, tag); - } - } - } - - // Do the rest of the types. - int numTypes = in.readInt(); - if (DEBUG) { - Slog.d(TAG, "Reading " + numTypes + " elements"); - } - for (int i = 0; i < numTypes; i++) { - int type = in.readInt(); - mTypes.add(type); - switch (type) { - case EVENT_TYPE_INT: - mValues.add(in.readInt()); - break; - case EVENT_TYPE_LONG: - mValues.add(in.readLong()); - break; - case EVENT_TYPE_FLOAT: - mValues.add(in.readFloat()); - break; - case EVENT_TYPE_DOUBLE: - mValues.add(in.readDouble()); - break; - case EVENT_TYPE_STRING: - mValues.add(in.readString()); - break; - case EVENT_TYPE_STORAGE: - mValues.add(in.createByteArray()); - break; - default: - break; - } - } - } - - /** - * Boilerplate for Parcel. - */ - public int describeContents() { - return 0; - } -} diff --git a/core/java/android/os/TelephonyServiceManager.java b/core/java/android/os/TelephonyServiceManager.java index c93eba6523f0..c67dedb4ac17 100644 --- a/core/java/android/os/TelephonyServiceManager.java +++ b/core/java/android/os/TelephonyServiceManager.java @@ -191,14 +191,6 @@ public class TelephonyServiceManager { } /** - * Returns {@link ServiceRegisterer} for the package manager service. - */ - @NonNull - public ServiceRegisterer getPackageManagerServiceRegisterer() { - return new ServiceRegisterer("package"); - } - - /** * Returns {@link ServiceRegisterer} for the ICC phone book service. */ @NonNull diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 5a1ba7fe534c..4812ea98b569 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -266,6 +266,28 @@ public final class PermissionManager { } } + /** + * Grant default permissions to currently enabled carrier apps + * @param packageNames Package names of the apps to be granted permissions + * @param user The user handle + * @param executor The executor for the callback + * @param callback The callback provided by caller to be notified when grant completes + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) + public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[] packageNames, + @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> callback) { + try { + mPermissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, + user.getIdentifier()); + executor.execute(() -> callback.accept(true)); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList( List<SplitPermissionInfoParcelable> parcelableList) { final int size = parcelableList.size(); @@ -416,4 +438,4 @@ public final class PermissionManager { e.rethrowFromSystemServer(); } } -} +}
\ No newline at end of file diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 38768c393e18..a62412068fda 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9362,6 +9362,16 @@ public final class Settings { public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM = "enable_sizecompat_freeform"; + /** + * If true, shadows drawn around the window will be rendered by the system compositor. If + * false, shadows will be drawn by the client by setting an elevation on the root view and + * the contents will be inset by the surface insets. + * (0 = false, 1 = true) + * @hide + */ + public static final String DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR = + "render_shadows_in_compositor"; + /** * Whether user has enabled development settings. */ @@ -9737,6 +9747,15 @@ public final class Settings { */ public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs"; + /** + * Run integrity checks for integrity rule providers. + * 0 = bypass integrity verification on installs from rule providers (default) + * 1 = perform integrity verification on installs from rule providers + * @hide + */ + public static final String INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER = + "verify_integrity_for_rule_provider"; + /** * Time since last fstrim (milliseconds) after which we force one to happen * during device startup. If unset, the default is 3 days. @@ -11082,6 +11101,15 @@ public final class Settings { = "activity_starts_logging_enabled"; /** + * Feature flag to enable or disable the foreground service starts logging feature. + * Type: int (0 for false, 1 for true) + * Default: 1 + * @hide + */ + public static final String FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED = + "foreground_service_starts_logging_enabled"; + + /** * @hide * @see com.android.server.appbinding.AppBindingConstants */ diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index f25cdf1b8c98..9da584ea1487 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -3745,6 +3745,7 @@ public final class Telephony { * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead */ @Deprecated + @SystemApi public static final String BEARER_BITMASK = "bearer_bitmask"; /** @@ -3794,6 +3795,7 @@ public final class Telephony { * <p>Type: INTEGER</p> *@hide */ + @SystemApi public static final String PROFILE_ID = "profile_id"; /** @@ -3994,6 +3996,7 @@ public final class Telephony { * * @hide */ + @SystemApi public static final String SKIP_464XLAT = "skip_464xlat"; /** @@ -4002,6 +4005,7 @@ public final class Telephony { * * @hide */ + @SystemApi public static final int SKIP_464XLAT_DEFAULT = -1; /** @@ -4010,6 +4014,7 @@ public final class Telephony { * * @hide */ + @SystemApi public static final int SKIP_464XLAT_DISABLE = 0; /** @@ -4018,6 +4023,7 @@ public final class Telephony { * * @hide */ + @SystemApi public static final int SKIP_464XLAT_ENABLE = 1; diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 3d82946876d1..ac2532dcea7d 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -34,9 +34,12 @@ import android.content.Intent; import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.Looper; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; import android.util.Slog; @@ -49,15 +52,20 @@ import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; import android.view.contentcapture.ContentCaptureSessionId; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; import android.view.contentcapture.IContentCaptureDirectManager; import android.view.contentcapture.MainContentCaptureSession; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * A service used to capture the content of the screen to provide contextual data in other areas of @@ -166,6 +174,12 @@ public abstract class ContentCaptureService extends Service { } @Override + public void onDataShared(DataShareRequest request, IDataShareCallback callback) { + mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnDataShared, + ContentCaptureService.this, request, callback)); + } + + @Override public void onActivityEvent(ActivityEvent event) { mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnActivityEvent, ContentCaptureService.this, event)); @@ -318,6 +332,21 @@ public abstract class ContentCaptureService extends Service { } /** + * Notifies the service that data has been shared via a readable file. + * + * @param request request object containing information about data being shared + * @param callback callback to be fired with response on whether the request is "needed" and can + * be handled by the Content Capture service. + * + * @hide + */ + @SystemApi + public void onDataShareRequest(@NonNull DataShareRequest request, + @NonNull DataShareCallback callback) { + if (sVerbose) Log.v(TAG, "onDataShareRequest()"); + } + + /** * Notifies the service of {@link SnapshotData snapshot data} associated with a session. * * @param sessionId the session's Id @@ -505,6 +534,40 @@ public abstract class ContentCaptureService extends Service { onDataRemovalRequest(request); } + private void handleOnDataShared(@NonNull DataShareRequest request, + IDataShareCallback callback) { + onDataShareRequest(request, new DataShareCallback() { + + @Override + public void onAccept(@NonNull Executor executor, + @NonNull DataShareReadAdapter adapter) { + Preconditions.checkNotNull(adapter); + Preconditions.checkNotNull(executor); + + ICancellationSignal cancellationSignalTransport = + CancellationSignal.createTransport(); + + DataShareReadAdapterDelegate delegate = new DataShareReadAdapterDelegate( + executor, cancellationSignalTransport, adapter); + + try { + callback.accept(cancellationSignalTransport, delegate); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to accept data sharing", e); + } + } + + @Override + public void onReject() { + try { + callback.reject(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to reject data sharing", e); + } + } + }); + } + private void handleOnActivityEvent(@NonNull ActivityEvent event) { onActivityEvent(event); } @@ -589,4 +652,71 @@ public abstract class ContentCaptureService extends Service { Log.e(TAG, "failed to write flush metrics: " + e); } } + + private static class DataShareReadAdapterDelegate extends IDataShareReadAdapter.Stub { + + private final Object mLock = new Object(); + private final WeakReference<DataShareReadAdapter> mAdapterReference; + private final WeakReference<Executor> mExecutorReference; + private final WeakReference<ICancellationSignal> mCancellationSignalReference; + + DataShareReadAdapterDelegate(Executor executor, + ICancellationSignal cancellationSignalTransport, DataShareReadAdapter adapter) { + Preconditions.checkNotNull(executor); + Preconditions.checkNotNull(cancellationSignalTransport); + Preconditions.checkNotNull(adapter); + + mExecutorReference = new WeakReference<>(executor); + mCancellationSignalReference = new WeakReference<>(cancellationSignalTransport); + mAdapterReference = new WeakReference<>(adapter); + } + + @Override + public void start(ParcelFileDescriptor fd, ICancellationSignal remoteCancellationSignal) + throws RemoteException { + synchronized (mLock) { + ICancellationSignal serverControlledCancellationSignal = + mCancellationSignalReference.get(); + + if (serverControlledCancellationSignal == null) { + Slog.w(TAG, "Can't execute onStart(), reference to cancellation signal has " + + "been GC'ed"); + return; + } + + CancellationSignal cancellationSignal = + CancellationSignal.fromTransport(serverControlledCancellationSignal); + cancellationSignal.setRemote(remoteCancellationSignal); + + executeAdapterMethodLocked( + adapter -> adapter.onStart(fd, cancellationSignal), "onStart"); + } + } + + @Override + public void error(int errorCode) throws RemoteException { + synchronized (mLock) { + executeAdapterMethodLocked( + adapter -> adapter.onError(errorCode), "onError"); + } + } + + private void executeAdapterMethodLocked(Consumer<DataShareReadAdapter> adapterFn, + String methodName) { + DataShareReadAdapter adapter = mAdapterReference.get(); + Executor executor = mExecutorReference.get(); + + if (adapter == null || executor == null) { + Slog.w(TAG, "Can't execute " + methodName + "(), references have been GC'ed"); + return; + } + + final long identity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> adapterFn.accept(adapter)); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } } diff --git a/core/java/android/service/contentcapture/DataShareCallback.java b/core/java/android/service/contentcapture/DataShareCallback.java new file mode 100644 index 000000000000..e3c7bb3cd24f --- /dev/null +++ b/core/java/android/service/contentcapture/DataShareCallback.java @@ -0,0 +1,47 @@ +/* + * 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 android.service.contentcapture; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import java.util.concurrent.Executor; + +/** + * Callback for the Content Capture Service to accept or reject the data share request from a client + * app. + * + * If the request is rejected, client app would receive a signal and the data share session wouldn't + * be started. + * + * @hide + **/ +@SystemApi +public interface DataShareCallback { + + /** Accept the data share. + * + * @param executor executor to be used for running the adapter in. + * @param adapter adapter to be used for the share operation + */ + void onAccept(@NonNull @CallbackExecutor Executor executor, + @NonNull DataShareReadAdapter adapter); + + /** Reject the data share. */ + void onReject(); +} diff --git a/core/java/android/service/contentcapture/DataShareReadAdapter.java b/core/java/android/service/contentcapture/DataShareReadAdapter.java new file mode 100644 index 000000000000..ca6820110ea9 --- /dev/null +++ b/core/java/android/service/contentcapture/DataShareReadAdapter.java @@ -0,0 +1,46 @@ +/* + * 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 android.service.contentcapture; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.CancellationSignal; +import android.os.ParcelFileDescriptor; + +/** + * Adapter class to be used for the Content Capture Service app to propagate the status of the + * session + * + * @hide + **/ +@SystemApi +public interface DataShareReadAdapter { + + /** + * Signals the start of the data sharing session. + * + * @param fd file descriptor to use for reading data, that's being shared + * @param cancellationSignal cancellation signal to use if data is no longer needed and the + * session needs to be terminated. + **/ + void onStart(@NonNull ParcelFileDescriptor fd, @NonNull CancellationSignal cancellationSignal); + + /** + * Signals that the session failed to start or terminated unsuccessfully. + **/ + void onError(int errorCode); +} diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl index a7578af94004..277d82b5d909 100644 --- a/core/java/android/service/contentcapture/IContentCaptureService.aidl +++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl @@ -20,8 +20,10 @@ import android.content.ComponentName; import android.os.IBinder; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.SnapshotData; +import android.service.contentcapture.IDataShareCallback; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; import com.android.internal.os.IResultReceiver; @@ -40,5 +42,6 @@ oneway interface IContentCaptureService { void onSessionFinished(int sessionId); void onActivitySnapshot(int sessionId, in SnapshotData snapshotData); void onDataRemovalRequest(in DataRemovalRequest request); + void onDataShared(in DataShareRequest request, in IDataShareCallback callback); void onActivityEvent(in ActivityEvent event); } diff --git a/cmds/statsd/src/external/CarStatsPuller.h b/core/java/android/service/contentcapture/IDataShareCallback.aidl index ca0f1a9c9a17..d972adadb53c 100644 --- a/cmds/statsd/src/external/CarStatsPuller.h +++ b/core/java/android/service/contentcapture/IDataShareCallback.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,13 @@ * limitations under the License. */ -#pragma once +package android.service.contentcapture; -#include "StatsPuller.h" +import android.os.ICancellationSignal; +import android.service.contentcapture.IDataShareReadAdapter; -namespace android { -namespace os { -namespace statsd { - -/** - * Pull atoms from CarService. - */ -class CarStatsPuller : public StatsPuller { -public: - explicit CarStatsPuller(const int tagId); - bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override; -}; - -} // namespace statsd -} // namespace os -} // namespace android +/** @hide */ +oneway interface IDataShareCallback { + void accept(in ICancellationSignal cancellationSignal, in IDataShareReadAdapter adapter); + void reject(); +} diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.aidl b/core/java/android/service/contentcapture/IDataShareReadAdapter.aidl index f18c4dfd2dcd..73da5d515edc 100644 --- a/telephony/java/android/telephony/ims/RcsEventQueryParams.aidl +++ b/core/java/android/service/contentcapture/IDataShareReadAdapter.aidl @@ -1,12 +1,11 @@ /* - * - * Copyright 2019, The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,6 +14,12 @@ * limitations under the License. */ -package android.telephony.ims; +package android.service.contentcapture; + +import android.os.ICancellationSignal; -parcelable RcsEventQueryParams; +/** @hide */ +oneway interface IDataShareReadAdapter { + void start(in ParcelFileDescriptor fd, in ICancellationSignal cancellationSignal); + void error(int errorCode); +} diff --git a/core/java/android/service/controls/TokenProvider.aidl b/core/java/android/service/controls/TokenProvider.aidl new file mode 100644 index 000000000000..8f4b7953f659 --- /dev/null +++ b/core/java/android/service/controls/TokenProvider.aidl @@ -0,0 +1,7 @@ +package android.service.controls; + +/** @hide */ +interface TokenProvider { + void setAuthToken(String token); + String getAccountName(); +}
\ No newline at end of file diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index 7815864ddfe9..26c831428f1c 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -1259,6 +1259,7 @@ public abstract class TextToSpeechService extends Service { @Override public IBinder onBind(Intent intent) { if (TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE.equals(intent.getAction())) { + Binder.allowBlocking(mBinder.asBinder()); return mBinder; } return null; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index d9c502e14e68..e1f1581c53bc 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -558,12 +558,6 @@ interface IWindowManager boolean isWindowTraceEnabled(); /** - * Requests that the WindowManager sends - * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. - */ - void requestUserActivityNotification(); - - /** * Notify WindowManager that it should not override the info in DisplayManager for the specified * display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics * of the logical display reported from WindowManager do not correspond to the metrics of the @@ -748,4 +742,9 @@ interface IWindowManager void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId, out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout); + + /** + * Called to show global actions. + */ + void showGlobalActions(); } diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index a6b7c33de3d9..78a080de20e5 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -858,11 +858,12 @@ public class Surface implements Parcelable { * surface is consumed by something other than the system compositor, e.g. a media * codec, this call has no effect. * - * @param frameRate The intended frame rate of this surface. 0 is a special value that - * indicates the app will accept the system's choice for the display frame rate, which - * is the default behavior if this function isn't called. The frameRate param does - * *not* need to be a valid refresh rate for this device's display - e.g., it's fine - * to pass 30fps to a device that can only run the display at 60fps. + * @param frameRate The intended frame rate of this surface, in frames per second. 0 + * is a special value that indicates the app will accept the system's choice for the + * display frame rate, which is the default behavior if this function isn't + * called. The frameRate param does *not* need to be a valid refresh rate for this + * device's display - e.g., it's fine to pass 30fps to a device that can only run the + * display at 60fps. */ public void setFrameRate(@FloatRange(from = 0.0) float frameRate) { int error = nativeSetFrameRate(mNativeObject, frameRate); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index f7b87cce7338..bee05a9a57d0 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2551,6 +2551,7 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ + @Deprecated @UnsupportedAppUsage public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface, long frameNumber) { @@ -2800,12 +2801,12 @@ public final class SurfaceControl implements Parcelable { * the system releases buffers back to the application. * * @param sc The SurfaceControl to specify the frame rate of. - * @param frameRate The intended frame rate for this surface. 0 is a special value that - * indicates the app will accept the system's choice for the display frame - * rate, which is the default behavior if this function isn't called. The - * frameRate param does *not* need to be a valid refresh rate for this - * device's display - e.g., it's fine to pass 30fps to a device that can - * only run the display at 60fps. + * @param frameRate The intended frame rate for this surface, in frames per second. 0 is a + * special value that indicates the app will accept the system's choice for + * the display frame rate, which is the default behavior if this function + * isn't called. The frameRate param does *not* need to be a valid refresh + * rate for this device's display - e.g., it's fine to pass 30fps to a + * device that can only run the display at 60fps. * @return This transaction object. */ @NonNull diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 1981bdd93eeb..75d5538faedd 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -414,7 +414,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } t.setAlpha(mSurfaceControl, alpha); if (!useBLAST) { - t.deferTransactionUntilSurface(mSurfaceControl, parent, frame); + t.deferTransactionUntil(mSurfaceControl, + viewRoot.getRenderSurfaceControl(), frame); } } // It's possible that mSurfaceControl is released in the UI thread before @@ -1122,7 +1123,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (frameNumber > 0 && !WindowManagerGlobal.USE_BLAST_ADAPTER) { final ViewRootImpl viewRoot = getViewRootImpl(); - t.deferTransactionUntilSurface(surface, viewRoot.mSurface, + t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(), frameNumber); } @@ -1217,8 +1218,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (frameNumber > 0 && viewRoot != null && !useBLAST) { if (viewRoot.mSurface.isValid()) { - mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, - frameNumber); + mRtTransaction.deferTransactionUntil(mSurfaceControl, + viewRoot.getRenderSurfaceControl(), frameNumber); } } t.hide(mSurfaceControl); diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java index a6536f5d83b7..abe44f45aba5 100644 --- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java +++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java @@ -38,7 +38,7 @@ public class SyncRtSurfaceTransactionApplier { public static final int FLAG_CORNER_RADIUS = 1 << 4; public static final int FLAG_VISIBILITY = 1 << 5; - private final Surface mTargetSurface; + private SurfaceControl mTargetSc; private final ViewRootImpl mTargetViewRootImpl; private final float[] mTmpFloat9 = new float[9]; @@ -47,7 +47,6 @@ public class SyncRtSurfaceTransactionApplier { */ public SyncRtSurfaceTransactionApplier(View targetView) { mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; - mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null; } /** @@ -60,15 +59,16 @@ public class SyncRtSurfaceTransactionApplier { if (mTargetViewRootImpl == null) { return; } + mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl(); mTargetViewRootImpl.registerRtFrameCallback(frame -> { - if (mTargetSurface == null || !mTargetSurface.isValid()) { + if (mTargetSc == null || !mTargetSc.isValid()) { return; } Transaction t = new Transaction(); for (int i = params.length - 1; i >= 0; i--) { SurfaceParams surfaceParams = params[i]; SurfaceControl surface = surfaceParams.surface; - t.deferTransactionUntilSurface(surface, mTargetSurface, frame); + t.deferTransactionUntil(surface, mTargetSc, frame); applyParams(t, surfaceParams, mTmpFloat9); } t.setEarlyWakeup(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f5cfbec924ac..7a93dcc9e4ec 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1733,8 +1733,8 @@ public final class ViewRootImpl implements ViewParent, private void updateBoundsLayer() { if (mBoundsLayer != null) { setBoundsLayerCrop(); - mTransaction.deferTransactionUntilSurface(mBoundsLayer, - mSurface, mSurface.getNextFrameNumber()) + mTransaction.deferTransactionUntil(mBoundsLayer, + getRenderSurfaceControl(), mSurface.getNextFrameNumber()) .apply(); } } @@ -9539,4 +9539,12 @@ public final class ViewRootImpl implements ViewParent, SurfaceControl.Transaction getBLASTSyncTransaction() { return mRtBLASTSyncTransaction; } + + SurfaceControl getRenderSurfaceControl() { + if (WindowManagerGlobal.USE_BLAST_ADAPTER) { + return mBlastSurfaceControl; + } else { + return mSurfaceControl; + } + } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 55c298e2a92b..a6450a10561b 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2459,6 +2459,7 @@ public interface WindowManager extends ViewManager { * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} * will be used. */ + @ActivityInfo.ScreenOrientation public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; /** diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java index a22f5a576ab6..492ab6f8a3d5 100644 --- a/core/java/android/view/WindowManagerPolicyConstants.java +++ b/core/java/android/view/WindowManagerPolicyConstants.java @@ -66,12 +66,6 @@ public interface WindowManagerPolicyConstants { String NAV_BAR_MODE_GESTURAL_OVERLAY = "com.android.internal.systemui.navbar.gestural"; /** - * Broadcast sent when a user activity is detected. - */ - String ACTION_USER_ACTIVITY_NOTIFICATION = - "android.intent.action.USER_ACTIVITY_NOTIFICATION"; - - /** * Sticky broadcast of the current HDMI plugged state. */ String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED"; diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 9cbba87e6856..02b098b27974 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -102,6 +102,12 @@ public final class AccessibilityManager { public static final int STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED = 0x00000004; /** @hide */ + public static final int STATE_FLAG_DISPATCH_DOUBLE_TAP = 0x00000008; + + /** @hide */ + public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000010; + + /** @hide */ public static final int DALTONIZER_DISABLED = -1; /** @hide */ diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 6040abd4f5f6..cede3b5cf9fe 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -19,6 +19,7 @@ import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import static android.view.contentcapture.ContentCaptureHelper.toSet; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,12 +31,17 @@ import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; import android.graphics.Canvas; +import android.os.Binder; +import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.Looper; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.Slog; import android.view.View; import android.view.ViewStructure; import android.view.WindowManager; @@ -48,8 +54,11 @@ import com.android.internal.util.SyncResultReceiver; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * <p>The {@link ContentCaptureManager} provides additional ways for for apps to @@ -629,6 +638,36 @@ public final class ContentCaptureManager { } /** + * Called by the app to request data sharing via writing to a file. + * + * <p>The ContentCaptureService app will receive a read-only file descriptor pointing to the + * same file and will be able to read data being shared from it. + * + * <p>Note: using this API doesn't guarantee the app staying alive and is "best-effort". + * Starting a foreground service would minimize the chances of the app getting killed during the + * file sharing session. + * + * @param request object specifying details of the data being shared. + */ + public void shareData(@NonNull DataShareRequest request, + @NonNull @CallbackExecutor Executor executor, + @NonNull DataShareWriteAdapter dataShareWriteAdapter) { + Preconditions.checkNotNull(request); + Preconditions.checkNotNull(dataShareWriteAdapter); + Preconditions.checkNotNull(executor); + + ICancellationSignal cancellationSignalTransport = CancellationSignal.createTransport(); + + try { + mService.shareData(request, cancellationSignalTransport, + new DataShareAdapterDelegate(executor, + cancellationSignalTransport, dataShareWriteAdapter)); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** * Runs a sync method in the service, properly handling exceptions. * * @throws SecurityException if caller is not allowed to execute the method. @@ -675,4 +714,65 @@ public final class ContentCaptureManager { private interface MyRunnable { void run(@NonNull SyncResultReceiver receiver) throws RemoteException; } + + private static class DataShareAdapterDelegate extends IDataShareWriteAdapter.Stub { + + private final WeakReference<DataShareWriteAdapter> mAdapterReference; + private final WeakReference<Executor> mExecutorReference; + private final WeakReference<ICancellationSignal> mCancellationSignal; + + private DataShareAdapterDelegate(Executor executor, + ICancellationSignal cancellationSignalTransport, DataShareWriteAdapter adapter) { + Preconditions.checkNotNull(executor); + Preconditions.checkNotNull(cancellationSignalTransport); + Preconditions.checkNotNull(adapter); + + mExecutorReference = new WeakReference<>(executor); + mAdapterReference = new WeakReference<>(adapter); + mCancellationSignal = new WeakReference<>(cancellationSignalTransport); + } + + @Override + public void write(ParcelFileDescriptor destination) + throws RemoteException { + ICancellationSignal cancellationSignalTransport = mCancellationSignal.get(); + if (cancellationSignalTransport == null) { + Slog.w(TAG, "Can't execute write(), reference to cancellation signal has been " + + "GC'ed"); + } + CancellationSignal cancellationSignal = + CancellationSignal.fromTransport(cancellationSignalTransport); + + executeAdapterMethodLocked(adapter -> adapter.onWrite(destination, cancellationSignal), + "onWrite"); + } + + @Override + public void error(int errorCode) throws RemoteException { + executeAdapterMethodLocked(adapter -> adapter.onError(errorCode), "onError"); + } + + @Override + public void rejected() throws RemoteException { + executeAdapterMethodLocked(DataShareWriteAdapter::onRejected, "onRejected"); + } + + private void executeAdapterMethodLocked(Consumer<DataShareWriteAdapter> adapterFn, + String methodName) { + DataShareWriteAdapter adapter = mAdapterReference.get(); + Executor executor = mExecutorReference.get(); + + if (adapter == null || executor == null) { + Slog.w(TAG, "Can't execute " + methodName + "(), references have been GC'ed"); + return; + } + + final long identity = Binder.clearCallingIdentity(); + try { + executor.execute(() -> adapterFn.accept(adapter)); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } } diff --git a/core/java/android/os/StatsLogEventWrapper.aidl b/core/java/android/view/contentcapture/DataShareRequest.aidl index 766343e38f3f..75073e411ec8 100644 --- a/core/java/android/os/StatsLogEventWrapper.aidl +++ b/core/java/android/view/contentcapture/DataShareRequest.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package android.view.contentcapture; -package android.os; - -/** @hide */ -parcelable StatsLogEventWrapper cpp_header "android/os/StatsLogEventWrapper.h";
\ No newline at end of file +parcelable DataShareRequest; diff --git a/core/java/android/view/contentcapture/DataShareRequest.java b/core/java/android/view/contentcapture/DataShareRequest.java new file mode 100644 index 000000000000..78c0ef9568ba --- /dev/null +++ b/core/java/android/view/contentcapture/DataShareRequest.java @@ -0,0 +1,207 @@ +/* + * 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 android.view.contentcapture; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityThread; +import android.content.LocusId; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Preconditions; + +/** Container class representing a request to share data with Content Capture service. */ +@DataClass( + genConstructor = false, + genEqualsHashCode = true, + genHiddenConstDefs = true, + genParcelable = true, + genToString = true +) +public final class DataShareRequest implements Parcelable { + + /** Name of the package making the request. */ + @NonNull private final String mPackageName; + + /** Locus id helping to identify what data is being shared. */ + @Nullable private final LocusId mLocusId; + + /** MIME type of the data being shared. */ + @NonNull private final String mMimeType; + + /** Constructs a request to share data with the Content Capture Service. */ + public DataShareRequest(@Nullable LocusId locusId, @NonNull String mimeType) { + Preconditions.checkNotNull(mimeType); + + mPackageName = ActivityThread.currentActivityThread().getApplication().getPackageName(); + mLocusId = locusId; + mMimeType = mimeType; + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/contentcapture/DataShareRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Name of the package making the request. + */ + @DataClass.Generated.Member + public @NonNull String getPackageName() { + return mPackageName; + } + + /** + * Locus id helping to identify what data is being shared. + */ + @DataClass.Generated.Member + public @Nullable LocusId getLocusId() { + return mLocusId; + } + + /** + * MIME type of the data being shared. + */ + @DataClass.Generated.Member + public @NonNull String getMimeType() { + return mMimeType; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "DataShareRequest { " + + "packageName = " + mPackageName + ", " + + "locusId = " + mLocusId + ", " + + "mimeType = " + mMimeType + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(DataShareRequest other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + DataShareRequest that = (DataShareRequest) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mPackageName, that.mPackageName) + && java.util.Objects.equals(mLocusId, that.mLocusId) + && java.util.Objects.equals(mMimeType, that.mMimeType); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mPackageName); + _hash = 31 * _hash + java.util.Objects.hashCode(mLocusId); + _hash = 31 * _hash + java.util.Objects.hashCode(mMimeType); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mLocusId != null) flg |= 0x2; + dest.writeByte(flg); + dest.writeString(mPackageName); + if (mLocusId != null) dest.writeTypedObject(mLocusId, flags); + dest.writeString(mMimeType); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ DataShareRequest(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + String packageName = in.readString(); + LocusId locusId = (flg & 0x2) == 0 ? null : (LocusId) in.readTypedObject(LocusId.CREATOR); + String mimeType = in.readString(); + + this.mPackageName = packageName; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPackageName); + this.mLocusId = locusId; + this.mMimeType = mimeType; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMimeType); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<DataShareRequest> CREATOR + = new Parcelable.Creator<DataShareRequest>() { + @Override + public DataShareRequest[] newArray(int size) { + return new DataShareRequest[size]; + } + + @Override + public DataShareRequest createFromParcel(@NonNull Parcel in) { + return new DataShareRequest(in); + } + }; + + @DataClass.Generated( + time = 1579870254459L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/contentcapture/DataShareRequest.java", + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable android.content.LocusId mLocusId\nprivate final @android.annotation.NonNull java.lang.String mMimeType\nclass DataShareRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/contentcapture/DataShareWriteAdapter.java b/core/java/android/view/contentcapture/DataShareWriteAdapter.java new file mode 100644 index 000000000000..f791fea7ee8d --- /dev/null +++ b/core/java/android/view/contentcapture/DataShareWriteAdapter.java @@ -0,0 +1,58 @@ +/* + * 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 android.view.contentcapture; + +import android.annotation.NonNull; +import android.os.CancellationSignal; +import android.os.ParcelFileDescriptor; + +/** Adapter class used by apps to share data with the Content Capture service. */ +public interface DataShareWriteAdapter { + + /** Request has been rejected, because a concurrent data share sessions is in progress. */ + int ERROR_CONCURRENT_REQUEST = 1; + + /** Data share session timed out. */ + int ERROR_UNKNOWN = 2; + + /** + * Method invoked when the data share session has been started and the app needs to start + * writing into the file used for sharing. + * + * <p>App needs to handle explicitly cases when the file descriptor is closed and handle + * gracefully if IOExceptions happen. + * + * @param destination file descriptor used to write data into + * @param cancellationSignal cancellation signal that the app can use to subscribe to cancel + * operations. + */ + void onWrite(@NonNull ParcelFileDescriptor destination, + @NonNull CancellationSignal cancellationSignal); + + /** Data share sessions has been rejected by the Content Capture service. */ + void onRejected(); + + /** + * Method invoked when an error occurred, for example sessions has not been started or + * terminated unsuccessfully. + * + * @param errorCode the error code corresponding to an ERROR_* value. + */ + default void onError(int errorCode) { + /* do nothing - stub */ + } +} diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl index 7850b67b8404..5217e68eac50 100644 --- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl +++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl @@ -20,7 +20,10 @@ import android.content.ComponentName; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureEvent; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; +import android.view.contentcapture.IDataShareWriteAdapter; import android.os.IBinder; +import android.os.ICancellationSignal; import com.android.internal.os.IResultReceiver; @@ -64,6 +67,12 @@ oneway interface IContentCaptureManager { void removeData(in DataRemovalRequest request); /** + * Requests sharing of a binary data with the content capture service. + */ + void shareData(in DataShareRequest request, in ICancellationSignal cancellationSignal, + in IDataShareWriteAdapter adapter); + + /** * Returns whether the content capture feature is enabled for the calling user. */ void isContentCaptureFeatureEnabled(in IResultReceiver result); diff --git a/core/java/com/android/internal/car/ICarStatsService.aidl b/core/java/android/view/contentcapture/IDataShareWriteAdapter.aidl index 170b448ba33f..80924ef78f85 100644 --- a/core/java/com/android/internal/car/ICarStatsService.aidl +++ b/core/java/android/view/contentcapture/IDataShareWriteAdapter.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,18 +14,15 @@ * limitations under the License. */ -package com.android.internal.car; +package android.view.contentcapture; -import android.os.StatsLogEventWrapper; +import android.os.ICancellationSignal; /** - * Interface for pulling statsd atoms from automotive devices. - * * @hide */ -interface ICarStatsService { - /** - * Pull the specified atom. Results will be sent to statsd when complete. - */ - StatsLogEventWrapper[] pullData(int atomId); +oneway interface IDataShareWriteAdapter { + void write(in ParcelFileDescriptor destination); + void error(int errorCode); + void rejected(); } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 42d7892eeffb..c8a7c079994c 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -17,6 +17,7 @@ package android.widget; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkState; import android.annotation.IntDef; import android.annotation.NonNull; @@ -24,6 +25,9 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; @@ -105,15 +109,45 @@ public class Toast { */ public static final int LENGTH_LONG = 1; + /** + * Text toasts will be rendered by SystemUI instead of in-app, so apps can't circumvent + * background custom toast restrictions. + * + * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood + */ + @ChangeId + // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long CHANGE_TEXT_TOASTS_IN_THE_SYSTEM = 147798919L; + + private final Binder mToken; private final Context mContext; + private final Handler mHandler; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final TN mTN; @UnsupportedAppUsage int mDuration; - View mNextView; - // TODO(b/128611929): Remove this and check for null view when toast creation is in the system - boolean mIsCustomToast = false; + + /** + * This is also passed to {@link TN} object, where it's also accessed with itself as its own + * lock. + */ + @GuardedBy("mCallbacks") + private final List<Callback> mCallbacks; + + /** + * View to be displayed, in case this is a custom toast (e.g. not created with {@link + * #makeText(Context, int, int)} or its variants). + */ + @Nullable + private View mNextView; + + /** + * Text to be shown, in case this is NOT a custom toast (e.g. created with {@link + * #makeText(Context, int, int)} or its variants). + */ + @Nullable + private CharSequence mText; /** * Construct an empty Toast object. You must call {@link #setView} before you @@ -133,19 +167,34 @@ public class Toast { public Toast(@NonNull Context context, @Nullable Looper looper) { mContext = context; mToken = new Binder(); - mTN = new TN(context.getPackageName(), mToken, looper); + looper = getLooper(looper); + mHandler = new Handler(looper); + mCallbacks = new ArrayList<>(); + mTN = new TN(context.getPackageName(), mToken, mCallbacks, looper); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); } + private Looper getLooper(@Nullable Looper looper) { + if (looper != null) { + return looper; + } + return checkNotNull(Looper.myLooper(), + "Can't toast on a thread that has not called Looper.prepare()"); + } + /** * Show the view for the specified duration. */ public void show() { - if (mNextView == null) { - throw new RuntimeException("setView must have been called"); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + checkState(mNextView != null || mText != null, "You must either set a text or a view"); + } else { + if (mNextView == null) { + throw new RuntimeException("setView must have been called"); + } } INotificationManager service = getService(); @@ -155,10 +204,18 @@ public class Toast { final int displayId = mContext.getDisplayId(); try { - if (mIsCustomToast) { - service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + if (mNextView != null) { + // It's a custom toast + service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + } else { + // It's a text toast + ITransientNotificationCallback callback = + new CallbackBinder(mCallbacks, mHandler); + service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback); + } } else { - service.enqueueTextToast(pkg, mToken, tn, mDuration, displayId); + service.enqueueToast(pkg, mToken, tn, mDuration, displayId); } } catch (RemoteException e) { // Empty @@ -171,7 +228,16 @@ public class Toast { * after the appropriate duration. */ public void cancel() { - mTN.cancel(); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM) + && mNextView == null) { + try { + getService().cancelToast(mContext.getOpPackageName(), mToken); + } catch (RemoteException e) { + // Empty + } + } else { + mTN.cancel(); + } } /** @@ -187,7 +253,6 @@ public class Toast { */ @Deprecated public void setView(View view) { - mIsCustomToast = true; mNextView = view; } @@ -203,7 +268,6 @@ public class Toast { * will not have custom toast views displayed. */ public View getView() { - mIsCustomToast = true; return mNextView; } @@ -298,8 +362,8 @@ public class Toast { */ public void addCallback(@NonNull Callback callback) { checkNotNull(callback); - synchronized (mTN.mCallbacks) { - mTN.mCallbacks.add(callback); + synchronized (mCallbacks) { + mCallbacks.add(callback); } } @@ -307,8 +371,8 @@ public class Toast { * Removes a callback previously added with {@link #addCallback(Callback)}. */ public void removeCallback(@NonNull Callback callback) { - synchronized (mTN.mCallbacks) { - mTN.mCallbacks.remove(callback); + synchronized (mCallbacks) { + mCallbacks.remove(callback); } } @@ -338,22 +402,30 @@ public class Toast { /** * Make a standard toast to display using the specified looper. * If looper is null, Looper.myLooper() is used. + * * @hide */ public static Toast makeText(@NonNull Context context, @Nullable Looper looper, @NonNull CharSequence text, @Duration int duration) { - Toast result = new Toast(context, looper); - - LayoutInflater inflate = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); - TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); - tv.setText(text); - - result.mNextView = v; - result.mDuration = duration; - - return result; + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + Toast result = new Toast(context, looper); + result.mText = text; + result.mDuration = duration; + return result; + } else { + Toast result = new Toast(context, looper); + + LayoutInflater inflate = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); + TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message); + tv.setText(text); + + result.mNextView = v; + result.mDuration = duration; + + return result; + } } /** @@ -385,14 +457,23 @@ public class Toast { * @param s The new text for the Toast. */ public void setText(CharSequence s) { - if (mNextView == null) { - throw new RuntimeException("This Toast was not created with Toast.makeText()"); - } - TextView tv = mNextView.findViewById(com.android.internal.R.id.message); - if (tv == null) { - throw new RuntimeException("This Toast was not created with Toast.makeText()"); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + if (mNextView != null) { + throw new IllegalStateException( + "Text provided for custom toast, remove previous setView() calls if you " + + "want a text toast instead."); + } + mText = s; + } else { + if (mNextView == null) { + throw new RuntimeException("This Toast was not created with Toast.makeText()"); + } + TextView tv = mNextView.findViewById(com.android.internal.R.id.message); + if (tv == null) { + throw new RuntimeException("This Toast was not created with Toast.makeText()"); + } + tv.setText(s); } - tv.setText(s); } // ======================================================================================= @@ -442,12 +523,18 @@ public class Toast { final Binder mToken; @GuardedBy("mCallbacks") - private final List<Callback> mCallbacks = new ArrayList<>(); + private final List<Callback> mCallbacks; static final long SHORT_DURATION_TIMEOUT = 4000; static final long LONG_DURATION_TIMEOUT = 7000; - TN(String packageName, Binder token, @Nullable Looper looper) { + /** + * Creates a {@link ITransientNotification} object. + * + * The parameter {@code callbacks} is not copied and is accessed with itself as its own + * lock. + */ + TN(String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately. final WindowManager.LayoutParams params = mParams; @@ -464,15 +551,8 @@ public class Toast { mPackageName = packageName; mToken = token; + mCallbacks = callbacks; - if (looper == null) { - // Use Looper.myLooper() if looper is not specified. - looper = Looper.myLooper(); - if (looper == null) { - throw new RuntimeException( - "Can't toast on a thread that has not called Looper.prepare()"); - } - } mHandler = new Handler(looper, null) { @Override public void handleMessage(Message msg) { @@ -655,4 +735,46 @@ public class Toast { */ public void onToastHidden() {} } + + private static class CallbackBinder extends ITransientNotificationCallback.Stub { + private final Handler mHandler; + + @GuardedBy("mCallbacks") + private final List<Callback> mCallbacks; + + /** + * Creates a {@link ITransientNotificationCallback} object. + * + * The parameter {@code callbacks} is not copied and is accessed with itself as its own + * lock. + */ + private CallbackBinder(List<Callback> callbacks, Handler handler) { + mCallbacks = callbacks; + mHandler = handler; + } + + @Override + public void onToastShown() { + mHandler.post(() -> { + for (Callback callback : getCallbacks()) { + callback.onToastShown(); + } + }); + } + + @Override + public void onToastHidden() { + mHandler.post(() -> { + for (Callback callback : getCallbacks()) { + callback.onToastHidden(); + } + }); + } + + private List<Callback> getCallbacks() { + synchronized (mCallbacks) { + return new ArrayList<>(mCallbacks); + } + } + } } diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java index b2aa0431251d..77d8e0290f20 100644 --- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -156,14 +156,32 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { @VisibleForTesting public abstract Object getAdapterForIndex(int pageIndex); + /** + * Returns the {@link ResolverListAdapter} instance of the profile that represents + * <code>userHandle</code>. If there is no such adapter for the specified + * <code>userHandle</code>, returns {@code null}. + * <p>For example, if there is a work profile on the device with user id 10, calling this method + * with <code>UserHandle.of(10)</code> returns the work profile {@link ResolverListAdapter}. + */ + @Nullable + abstract ResolverListAdapter getListAdapterForUserHandle(UserHandle userHandle); + + /** + * Returns the {@link ResolverListAdapter} instance of the profile that is currently visible + * to the user. + * <p>For example, if the user is viewing the work tab in the share sheet, this method returns + * the work profile {@link ResolverListAdapter}. + * @see #getInactiveListAdapter() + */ @VisibleForTesting public abstract ResolverListAdapter getActiveListAdapter(); /** * If this is a device with a work profile, returns the {@link ResolverListAdapter} instance - * of the profile that is not the active one. Otherwise returns {@code null}. For example, - * if the share sheet is launched in the work profile, this method returns the personal - * profile {@link ResolverListAdapter}. + * of the profile that is <b><i>not</i></b> currently visible to the user. Otherwise returns + * {@code null}. + * <p>For example, if the user is viewing the work tab in the share sheet, this method returns + * the personal profile {@link ResolverListAdapter}. * @see #getActiveListAdapter() */ @VisibleForTesting diff --git a/core/java/com/android/internal/app/BlockedAppActivity.java b/core/java/com/android/internal/app/BlockedAppActivity.java deleted file mode 100644 index fbdbbfb06b78..000000000000 --- a/core/java/com/android/internal/app/BlockedAppActivity.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.app; - -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Slog; - -import com.android.internal.R; - -/** - * A dialog shown to the user when they try to launch an app that is not allowed in lock task - * mode. The intent to start this activity must be created with the static factory method provided - * below. - */ -public class BlockedAppActivity extends AlertActivity { - - private static final String TAG = "BlockedAppActivity"; - private static final String PACKAGE_NAME = "com.android.internal.app"; - private static final String EXTRA_BLOCKED_PACKAGE = PACKAGE_NAME + ".extra.BLOCKED_PACKAGE"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = getIntent(); - int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, /* defaultValue= */ -1); - if (userId < 0) { - Slog.wtf(TAG, "Invalid user: " + userId); - finish(); - return; - } - - String packageName = intent.getStringExtra(EXTRA_BLOCKED_PACKAGE); - if (TextUtils.isEmpty(packageName)) { - Slog.wtf(TAG, "Invalid package: " + packageName); - finish(); - return; - } - - CharSequence appLabel = getAppLabel(userId, packageName); - - mAlertParams.mTitle = getString(R.string.app_blocked_title); - mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel); - mAlertParams.mPositiveButtonText = getString(android.R.string.ok); - setupAlert(); - } - - private CharSequence getAppLabel(int userId, String packageName) { - PackageManager pm = getPackageManager(); - try { - ApplicationInfo aInfo = - pm.getApplicationInfoAsUser(packageName, /* flags= */ 0, userId); - return aInfo.loadLabel(pm); - } catch (PackageManager.NameNotFoundException ne) { - Slog.e(TAG, "Package " + packageName + " not found", ne); - } - return packageName; - } - - - /** Creates an intent that launches {@link BlockedAppActivity}. */ - public static Intent createIntent(int userId, String packageName) { - return new Intent() - .setClassName("android", BlockedAppActivity.class.getName()) - .putExtra(Intent.EXTRA_USER_ID, userId) - .putExtra(EXTRA_BLOCKED_PACKAGE, packageName); - } -} diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 8bbc343fa4ca..65128e4a2eda 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -72,7 +72,6 @@ import android.os.IBinder; import android.os.Message; import android.os.Parcelable; import android.os.PatternMatcher; -import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; @@ -90,6 +89,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.HashedStringCache; import android.util.Log; +import android.util.Pair; import android.util.Size; import android.util.Slog; import android.view.LayoutInflater; @@ -150,6 +150,8 @@ public class ChooserActivity extends ResolverActivity implements ChooserListAdapter.ChooserListCommunicator, SelectableTargetInfoCommunicator { private static final String TAG = "ChooserActivity"; + private AppPredictor mPersonalAppPredictor; + private AppPredictor mWorkAppPredictor; @UnsupportedAppUsage public ChooserActivity() { @@ -164,7 +166,7 @@ public class ChooserActivity extends ResolverActivity implements private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private static final boolean USE_PREDICTION_MANAGER_FOR_SHARE_ACTIVITIES = true; // TODO(b/123088566) Share these in a better way. @@ -177,9 +179,8 @@ public class ChooserActivity extends ResolverActivity implements public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250; private boolean mIsAppPredictorComponentAvailable; - private AppPredictor mAppPredictor; - private AppPredictor.Callback mAppPredictorCallback; private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache; + private Map<ChooserTarget, ShortcutInfo> mDirectShareShortcutInfoCache; public static final int TARGET_TYPE_DEFAULT = 0; public static final int TARGET_TYPE_CHOOSER_TARGET = 1; @@ -239,7 +240,7 @@ public class ChooserActivity extends ResolverActivity implements private static final int MAX_RANKED_TARGETS = 4; private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>(); - private final Set<ComponentName> mServicesRequested = new HashSet<>(); + private final Set<Pair<ComponentName, UserHandle>> mServicesRequested = new HashSet<>(); private static final int MAX_LOG_RANK_POSITION = 12; @@ -422,6 +423,7 @@ public class ChooserActivity extends ResolverActivity implements WATCHDOG_TIMEOUT_MIN_MILLIS); sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT, WATCHDOG_TIMEOUT_MAX_MILLIS); + } private void maybeStopServiceRequestTimer() { @@ -454,10 +456,14 @@ public class ChooserActivity extends ResolverActivity implements break; } if (sri.resultTargets != null) { - // TODO(arangelov): Instead of using getCurrentListAdapter(), pass the - // profileId as part of the message. - mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults( - sri.originalTarget, sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET); + ChooserListAdapter adapterForUserHandle = + mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle( + sri.userHandle); + if (adapterForUserHandle != null) { + adapterForUserHandle.addServiceResults(sri.originalTarget, + sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET, + /* directShareShortcutInfoCache */ null); + } } unbindService(sri.connection); sri.connection.destroy(); @@ -480,15 +486,23 @@ public class ChooserActivity extends ResolverActivity implements Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; "); } - mChooserMultiProfilePagerAdapter.getActiveListAdapter().refreshListView(); + UserHandle userHandle = (UserHandle) msg.obj; + mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle(userHandle) + .refreshListView(); break; case SHORTCUT_MANAGER_SHARE_TARGET_RESULT: if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT"); final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj; if (resultInfo.resultTargets != null) { - mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults( - resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1); + ChooserListAdapter adapterForUserHandle = + mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle( + resultInfo.userHandle); + if (adapterForUserHandle != null) { + adapterForUserHandle.addServiceResults( + resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1, + mDirectShareShortcutInfoCache); + } } break; @@ -638,45 +652,6 @@ public class ChooserActivity extends ResolverActivity implements .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType()) .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost)); - AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); - if (appPredictor != null) { - mDirectShareAppTargetCache = new HashMap<>(); - mAppPredictorCallback = resultList -> { - //TODO(arangelov) Take care of edge case when callback called after swiping tabs - if (isFinishing() || isDestroyed()) { - return; - } - if (mChooserMultiProfilePagerAdapter.getActiveListAdapter().getCount() == 0) { - return; - } - if (resultList.isEmpty()) { - // APS may be disabled, so try querying targets ourselves. - //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents. - // Investigate implications for work tab. - queryDirectShareTargets( - mChooserMultiProfilePagerAdapter.getActiveListAdapter(), true); - return; - } - final List<DisplayResolveInfo> driList = - getDisplayResolveInfos( - mChooserMultiProfilePagerAdapter.getActiveListAdapter()); - final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos = - new ArrayList<>(); - for (AppTarget appTarget : resultList) { - if (appTarget.getShortcutInfo() == null) { - continue; - } - shareShortcutInfos.add(new ShortcutManager.ShareShortcutInfo( - appTarget.getShortcutInfo(), - new ComponentName( - appTarget.getPackageName(), appTarget.getClassName()))); - } - sendShareShortcutInfoList(shareShortcutInfos, driList, resultList); - }; - appPredictor - .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback); - } - mChooserRowServiceSpacing = getResources() .getDimensionPixelSize(R.dimen.chooser_service_spacing); @@ -707,6 +682,54 @@ public class ChooserActivity extends ResolverActivity implements if (DEBUG) { Log.d(TAG, "System Time Cost is " + systemCost); } + + mDirectShareShortcutInfoCache = new HashMap<>(); + } + + private AppPredictor setupAppPredictorForUser(UserHandle userHandle, + AppPredictor.Callback appPredictorCallback) { + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(userHandle); + if (appPredictor == null) { + return null; + } + mDirectShareAppTargetCache = new HashMap<>(); + appPredictor.registerPredictionUpdates(this.getMainExecutor(), appPredictorCallback); + return appPredictor; + } + + private AppPredictor.Callback createAppPredictorCallback( + ChooserListAdapter chooserListAdapter) { + return resultList -> { + //TODO(arangelov) Take care of edge case when callback called after swiping tabs + if (isFinishing() || isDestroyed()) { + return; + } + if (chooserListAdapter.getCount() == 0) { + return; + } + if (resultList.isEmpty()) { + // APS may be disabled, so try querying targets ourselves. + //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents. + // Investigate implications for work tab. + queryDirectShareTargets(chooserListAdapter, true); + return; + } + final List<DisplayResolveInfo> driList = + getDisplayResolveInfos(chooserListAdapter); + final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos = + new ArrayList<>(); + for (AppTarget appTarget : resultList) { + if (appTarget.getShortcutInfo() == null) { + continue; + } + shareShortcutInfos.add(new ShortcutManager.ShareShortcutInfo( + appTarget.getShortcutInfo(), + new ComponentName( + appTarget.getPackageName(), appTarget.getClassName()))); + } + sendShareShortcutInfoList(shareShortcutInfos, driList, resultList, + chooserListAdapter.getUserHandle()); + }; } static SharedPreferences getPinnedSharedPrefs(Context context) { @@ -1260,9 +1283,9 @@ public class ChooserActivity extends ResolverActivity implements if (mPreviewCoord != null) mPreviewCoord.cancelLoads(); - if (mAppPredictor != null) { - mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback); - mAppPredictor.destroy(); + mChooserMultiProfilePagerAdapter.getActiveListAdapter().destroyAppPredictor(); + if (mChooserMultiProfilePagerAdapter.getInactiveListAdapter() != null) { + mChooserMultiProfilePagerAdapter.getInactiveListAdapter().destroyAppPredictor(); } } @@ -1312,7 +1335,8 @@ public class ChooserActivity extends ResolverActivity implements mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults( /* origTarget */ null, Lists.newArrayList(mCallerChooserTargets), - TARGET_TYPE_DEFAULT); + TARGET_TYPE_DEFAULT, + /* directShareShortcutInfoCache */ null); } } @@ -1541,8 +1565,10 @@ public class ChooserActivity extends ResolverActivity implements void queryTargetServices(ChooserListAdapter adapter) { mQueriedTargetServicesTimeMs = System.currentTimeMillis(); - final PackageManager pm = getPackageManager(); - ShortcutManager sm = (ShortcutManager) getSystemService(ShortcutManager.class); + Context selectedProfileContext = createContextAsUser( + adapter.getUserHandle(), 0 /* flags */); + final PackageManager pm = selectedProfileContext.getPackageManager(); + ShortcutManager sm = selectedProfileContext.getSystemService(ShortcutManager.class); int targetsToQuery = 0; for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) { @@ -1565,10 +1591,13 @@ public class ChooserActivity extends ResolverActivity implements final ComponentName serviceComponent = new ComponentName( ai.packageName, serviceName); - if (mServicesRequested.contains(serviceComponent)) { + UserHandle userHandle = adapter.getUserHandle(); + Pair<ComponentName, UserHandle> requestedItem = + new Pair<>(serviceComponent, userHandle); + if (mServicesRequested.contains(requestedItem)) { continue; } - mServicesRequested.add(serviceComponent); + mServicesRequested.add(requestedItem); final Intent serviceIntent = new Intent(ChooserTargetService.SERVICE_INTERFACE) .setComponent(serviceComponent); @@ -1596,13 +1625,14 @@ public class ChooserActivity extends ResolverActivity implements } final ChooserTargetServiceConnection conn = - new ChooserTargetServiceConnection(this, dri); + new ChooserTargetServiceConnection(this, dri, + adapter.getUserHandle()); - // Explicitly specify Process.myUserHandle instead of calling bindService + // Explicitly specify the user handle instead of calling bindService // to avoid the warning from calling from the system process without an explicit // user handle if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND, - Process.myUserHandle())) { + adapter.getUserHandle())) { if (DEBUG) { Log.d(TAG, "Binding service connection for target " + dri + " intent " + serviceIntent); @@ -1684,8 +1714,9 @@ public class ChooserActivity extends ResolverActivity implements private void queryDirectShareTargets( ChooserListAdapter adapter, boolean skipAppPredictionService) { mQueriedSharingShortcutsTimeMs = System.currentTimeMillis(); + UserHandle userHandle = adapter.getUserHandle(); if (!skipAppPredictionService) { - AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(); + AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled(userHandle); if (appPredictor != null) { appPredictor.requestPredictionUpdate(); return; @@ -1700,17 +1731,18 @@ public class ChooserActivity extends ResolverActivity implements final List<DisplayResolveInfo> driList = getDisplayResolveInfos(adapter); AsyncTask.execute(() -> { - //TODO(arangelov) use the selected probile tab's ShortcutManager - ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE); + Context selectedProfileContext = createContextAsUser(userHandle, 0 /* flags */); + ShortcutManager sm = (ShortcutManager) selectedProfileContext + .getSystemService(Context.SHORTCUT_SERVICE); List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter); - sendShareShortcutInfoList(resultList, driList, null); + sendShareShortcutInfoList(resultList, driList, null, userHandle); }); } private void sendShareShortcutInfoList( List<ShortcutManager.ShareShortcutInfo> resultList, List<DisplayResolveInfo> driList, - @Nullable List<AppTarget> appTargets) { + @Nullable List<AppTarget> appTargets, UserHandle userHandle) { if (appTargets != null && appTargets.size() != resultList.size()) { throw new RuntimeException("resultList and appTargets must have the same size." + " resultList.size()=" + resultList.size() @@ -1749,9 +1781,11 @@ public class ChooserActivity extends ResolverActivity implements List<ChooserTarget> chooserTargets = convertToChooserTarget( matchingShortcuts, resultList, appTargets, shortcutType); + + final Message msg = Message.obtain(); msg.what = ChooserHandler.SHORTCUT_MANAGER_SHARE_TARGET_RESULT; - msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null); + msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null, userHandle); msg.arg1 = shortcutType; mChooserHandler.sendMessage(msg); resultMessageSent = true; @@ -1842,6 +1876,9 @@ public class ChooserActivity extends ResolverActivity implements mDirectShareAppTargetCache.put(chooserTarget, allAppTargets.get(indexInAllShortcuts)); } + if (mDirectShareShortcutInfoCache != null) { + mDirectShareShortcutInfoCache.put(chooserTarget, shortcutInfo); + } } // Sort ChooserTargets by score in descending order Comparator<ChooserTarget> byScore = @@ -1915,7 +1952,8 @@ public class ChooserActivity extends ResolverActivity implements } private void sendClickToAppPredictor(TargetInfo targetInfo) { - AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled(); + AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled( + mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); if (directShareAppPredictor == null) { return; } @@ -1937,34 +1975,54 @@ public class ChooserActivity extends ResolverActivity implements } @Nullable - private AppPredictor getAppPredictor() { + private AppPredictor createAppPredictor(UserHandle userHandle) { if (!mIsAppPredictorComponentAvailable) { return null; } - if (mAppPredictor == null) { - final IntentFilter filter = getTargetIntentFilter(); - Bundle extras = new Bundle(); - extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); - AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(this) - .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) - .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) - .setExtras(extras) - .build(); - AppPredictionManager appPredictionManager - = getSystemService(AppPredictionManager.class); - mAppPredictor = appPredictionManager.createAppPredictionSession(appPredictionContext); + + if (getPersonalProfileUserHandle() == userHandle) { + if (mPersonalAppPredictor != null) { + return mPersonalAppPredictor; + } + } else { + if (mWorkAppPredictor != null) { + return mWorkAppPredictor; + } + } + + // TODO(b/148230574): Currently AppPredictor fetches only the same-profile app targets. + // Make AppPredictor work cross-profile. + Context contextAsUser = createContextAsUser(userHandle, 0 /* flags */); + final IntentFilter filter = getTargetIntentFilter(); + Bundle extras = new Bundle(); + extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter); + AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(contextAsUser) + .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE) + .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT) + .setExtras(extras) + .build(); + AppPredictionManager appPredictionManager = + contextAsUser + .getSystemService(AppPredictionManager.class); + AppPredictor appPredictionSession = appPredictionManager.createAppPredictionSession( + appPredictionContext); + if (getPersonalProfileUserHandle() == userHandle) { + mPersonalAppPredictor = appPredictionSession; + } else { + mWorkAppPredictor = appPredictionSession; } - return mAppPredictor; + return appPredictionSession; } /** * This will return an app predictor if it is enabled for direct share sorting * and if one exists. Otherwise, it returns null. + * @param userHandle */ @Nullable - private AppPredictor getAppPredictorForDirectShareIfEnabled() { + private AppPredictor getAppPredictorForDirectShareIfEnabled(UserHandle userHandle) { return ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS - && !ActivityManager.isLowRamDeviceStatic() ? getAppPredictor() : null; + && !ActivityManager.isLowRamDeviceStatic() ? createAppPredictor(userHandle) : null; } /** @@ -1972,8 +2030,8 @@ public class ChooserActivity extends ResolverActivity implements * and if one exists. Otherwise, it returns null. */ @Nullable - private AppPredictor getAppPredictorForShareActivitesIfEnabled() { - return USE_PREDICTION_MANAGER_FOR_SHARE_ACTIVITIES ? getAppPredictor() : null; + private AppPredictor getAppPredictorForShareActivitiesIfEnabled(UserHandle userHandle) { + return USE_PREDICTION_MANAGER_FOR_SHARE_ACTIVITIES ? createAppPredictor(userHandle) : null; } void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) { @@ -2016,12 +2074,13 @@ public class ChooserActivity extends ResolverActivity implements return false; } - void filterServiceTargets(String packageName, List<ChooserTarget> targets) { + void filterServiceTargets(Context contextAsUser, String packageName, + List<ChooserTarget> targets) { if (targets == null) { return; } - final PackageManager pm = getPackageManager(); + final PackageManager pm = contextAsUser.getPackageManager(); for (int i = targets.size() - 1; i >= 0; i--) { final ChooserTarget target = targets.get(i); final ComponentName targetName = target.getComponentName(); @@ -2104,19 +2163,24 @@ public class ChooserActivity extends ResolverActivity implements public ChooserGridAdapter createChooserGridAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { - return new ChooserGridAdapter( - new ChooserListAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, createListController(userHandle), useLayoutForBrowsables, - this, this)); + ChooserListAdapter chooserListAdapter = new ChooserListAdapter(context, payloadIntents, + initialIntents, rList, + filterLastUsed, createListController(userHandle), useLayoutForBrowsables, + this, this); + AppPredictor.Callback appPredictorCallback = createAppPredictorCallback(chooserListAdapter); + AppPredictor appPredictor = setupAppPredictorForUser(userHandle, appPredictorCallback); + chooserListAdapter.setAppPredictor(appPredictor); + chooserListAdapter.setAppPredictorCallback(appPredictorCallback); + return new ChooserGridAdapter(chooserListAdapter); } @VisibleForTesting protected ResolverListController createListController(UserHandle userHandle) { - AppPredictor appPredictor = getAppPredictorForShareActivitesIfEnabled(); + AppPredictor appPredictor = getAppPredictorForShareActivitiesIfEnabled(userHandle); AbstractResolverComparator resolverComparator; if (appPredictor != null) { resolverComparator = new AppPredictionServiceResolverComparator(this, getTargetIntent(), - getReferrerPackageName(), appPredictor, getUser()); + getReferrerPackageName(), appPredictor, userHandle); } else { resolverComparator = new ResolverRankerServiceResolverComparator(this, getTargetIntent(), @@ -2297,9 +2361,11 @@ public class ChooserActivity extends ResolverActivity implements } @Override // ChooserListCommunicator - public void sendListViewUpdateMessage() { - mChooserHandler.sendEmptyMessageDelayed(ChooserHandler.LIST_VIEW_UPDATE_MESSAGE, - LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); + public void sendListViewUpdateMessage(UserHandle userHandle) { + Message msg = Message.obtain(); + msg.what = ChooserHandler.LIST_VIEW_UPDATE_MESSAGE; + msg.obj = userHandle; + mChooserHandler.sendMessageDelayed(msg, LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); } @Override @@ -3158,6 +3224,7 @@ public class ChooserActivity extends ResolverActivity implements private DisplayResolveInfo mOriginalTarget; private ComponentName mConnectedComponent; private ChooserActivity mChooserActivity; + private final UserHandle mUserHandle; private final Object mLock = new Object(); private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() { @@ -3169,21 +3236,24 @@ public class ChooserActivity extends ResolverActivity implements + mConnectedComponent + "; ignoring..."); return; } - mChooserActivity.filterServiceTargets( + Context contextAsUser = + mChooserActivity.createContextAsUser(mUserHandle, 0 /* flags */); + mChooserActivity.filterServiceTargets(contextAsUser, mOriginalTarget.getResolveInfo().activityInfo.packageName, targets); final Message msg = Message.obtain(); msg.what = ChooserHandler.CHOOSER_TARGET_SERVICE_RESULT; msg.obj = new ServiceResultInfo(mOriginalTarget, targets, - ChooserTargetServiceConnection.this); + ChooserTargetServiceConnection.this, mUserHandle); mChooserActivity.mChooserHandler.sendMessage(msg); } } }; public ChooserTargetServiceConnection(ChooserActivity chooserActivity, - DisplayResolveInfo dri) { + DisplayResolveInfo dri, UserHandle userHandle) { mChooserActivity = chooserActivity; mOriginalTarget = dri; + mUserHandle = userHandle; } @Override @@ -3249,12 +3319,14 @@ public class ChooserActivity extends ResolverActivity implements public final DisplayResolveInfo originalTarget; public final List<ChooserTarget> resultTargets; public final ChooserTargetServiceConnection connection; + public final UserHandle userHandle; public ServiceResultInfo(DisplayResolveInfo ot, List<ChooserTarget> rt, - ChooserTargetServiceConnection c) { + ChooserTargetServiceConnection c, UserHandle userHandle) { originalTarget = ot; resultTargets = rt; connection = c; + this.userHandle = userHandle; } } diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index 6ff844a2eaae..ca3b7e7a7837 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -19,7 +19,9 @@ package com.android.internal.app; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; +import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.prediction.AppPredictor; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -27,7 +29,9 @@ import android.content.pm.ActivityInfo; import android.content.pm.LabeledIntent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; import android.os.AsyncTask; +import android.os.UserHandle; import android.os.UserManager; import android.service.chooser.ChooserTarget; import android.util.Log; @@ -90,6 +94,8 @@ public class ChooserListAdapter extends ResolverListAdapter { // Sorted list of DisplayResolveInfos for the alphabetical app section. private List<DisplayResolveInfo> mSortedList = new ArrayList<>(); + private AppPredictor mAppPredictor; + private AppPredictor.Callback mAppPredictorCallback; public ChooserListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, @@ -160,6 +166,10 @@ public class ChooserListAdapter extends ResolverListAdapter { } } + AppPredictor getAppPredictor() { + return mAppPredictor; + } + @Override public void handlePackagesChanged() { if (DEBUG) { @@ -173,7 +183,7 @@ public class ChooserListAdapter extends ResolverListAdapter { @Override public void notifyDataSetChanged() { if (!mListViewDataChanged) { - mChooserListCommunicator.sendListViewUpdateMessage(); + mChooserListCommunicator.sendListViewUpdateMessage(getUserHandle()); mListViewDataChanged = true; } } @@ -383,7 +393,8 @@ public class ChooserListAdapter extends ResolverListAdapter { * if score is too low. */ public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets, - @ChooserActivity.ShareTargetType int targetType) { + @ChooserActivity.ShareTargetType int targetType, + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos) { if (DEBUG) { Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size() + " targets"); @@ -412,8 +423,11 @@ public class ChooserListAdapter extends ResolverListAdapter { // This incents ChooserTargetServices to define what's truly better. targetScore = lastScore * 0.95f; } - boolean isInserted = insertServiceTarget(new SelectableTargetInfo( - mContext, origTarget, target, targetScore, mSelectableTargetInfoComunicator)); + UserHandle userHandle = getUserHandle(); + Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */); + boolean isInserted = insertServiceTarget(new SelectableTargetInfo(contextAsUser, + origTarget, target, targetScore, mSelectableTargetInfoComunicator, + (isShortcutResult ? directShareToShortcutInfos.get(target) : null))); if (isInserted && isShortcutResult) { mNumShortcutResults++; @@ -547,6 +561,21 @@ public class ChooserListAdapter extends ResolverListAdapter { }; } + public void setAppPredictor(AppPredictor appPredictor) { + mAppPredictor = appPredictor; + } + + public void setAppPredictorCallback(AppPredictor.Callback appPredictorCallback) { + mAppPredictorCallback = appPredictorCallback; + } + + public void destroyAppPredictor() { + if (getAppPredictor() != null) { + getAppPredictor().unregisterPredictionUpdates(mAppPredictorCallback); + getAppPredictor().destroy(); + } + } + /** * Necessary methods to communicate between {@link ChooserListAdapter} * and {@link ChooserActivity}. @@ -555,7 +584,7 @@ public class ChooserListAdapter extends ResolverListAdapter { int getMaxRankedTargets(); - void sendListViewUpdateMessage(); + void sendListViewUpdateMessage(UserHandle userHandle); boolean isSendAction(Intent targetIntent); } diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java index 1c52d0e8f9f1..663e0255feb9 100644 --- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -18,6 +18,7 @@ package com.android.internal.app; import android.annotation.Nullable; import android.content.Context; +import android.os.UserHandle; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -84,6 +85,18 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd } @Override + @Nullable + ChooserListAdapter getListAdapterForUserHandle(UserHandle userHandle) { + if (getActiveListAdapter().getUserHandle() == userHandle) { + return getActiveListAdapter(); + } else if (getInactiveListAdapter() != null + && getInactiveListAdapter().getUserHandle() == userHandle) { + return getInactiveListAdapter(); + } + return null; + } + + @Override void setupListAdapter(int pageIndex) { final RecyclerView recyclerView = getItem(pageIndex).recyclerView; ChooserActivity.ChooserGridAdapter chooserGridAdapter = diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 96ab0bb4afc4..30a41d338806 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -543,6 +543,9 @@ public class ResolverActivity extends Activity implements public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); + if (mMultiProfilePagerAdapter.getInactiveListAdapter() != null) { + mMultiProfilePagerAdapter.getInactiveListAdapter().handlePackagesChanged(); + } if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index d227ec5c1b38..405112d99fe7 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -407,6 +407,7 @@ public class ResolverListAdapter extends BaseAdapter { // We assume that at this point we've already filtered out the only intent for a different // targetUserId which we're going to use. private void addResolveInfo(DisplayResolveInfo dri) { + // TODO(arangelov): Is that UserHandle.USER_CURRENT check okay? if (dri != null && dri.getResolveInfo() != null && dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) { // Checks if this info is already listed in display. @@ -575,7 +576,7 @@ public class ResolverListAdapter extends BaseAdapter { Drawable loadIconForResolveInfo(ResolveInfo ri) { // Load icons based on the current process. If in work profile icons should be badged. - return makePresentationGetter(ri).getIcon(mResolverListController.getUserHandle()); + return makePresentationGetter(ri).getIcon(getUserHandle()); } void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) { @@ -585,6 +586,10 @@ public class ResolverListAdapter extends BaseAdapter { } } + UserHandle getUserHandle() { + return mResolverListController.getUserHandle(); + } + /** * Necessary methods to communicate between {@link ResolverListAdapter} * and {@link ResolverActivity}. diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java index 567ed74670bf..9d3c6c9ad8b1 100644 --- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java @@ -18,6 +18,7 @@ package com.android.internal.app; import android.annotation.Nullable; import android.content.Context; +import android.os.UserHandle; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.ListView; @@ -88,6 +89,18 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA } @Override + @Nullable + ResolverListAdapter getListAdapterForUserHandle(UserHandle userHandle) { + if (getActiveListAdapter().getUserHandle() == userHandle) { + return getActiveListAdapter(); + } else if (getInactiveListAdapter() != null + && getInactiveListAdapter().getUserHandle() == userHandle) { + return getInactiveListAdapter(); + } + return null; + } + + @Override @VisibleForTesting public ResolverListAdapter getActiveListAdapter() { return getAdapterForIndex(getCurrentPage()); diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java index c610ac4503c9..0589baa76b8a 100644 --- a/core/java/com/android/internal/app/SuspendedAppActivity.java +++ b/core/java/com/android/internal/app/SuspendedAppActivity.java @@ -18,23 +18,31 @@ package com.android.internal.app; 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.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; import static android.content.res.Resources.ID_NULL; import android.Manifest; +import android.annotation.Nullable; import android.app.AlertDialog; +import android.app.AppGlobals; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.SuspendDialogInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.view.WindowManager; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; public class SuspendedAppActivity extends AlertActivity implements DialogInterface.OnClickListener { @@ -46,8 +54,13 @@ public class SuspendedAppActivity extends AlertActivity PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE"; public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO"; public static final String EXTRA_ACTIVITY_OPTIONS = PACKAGE_NAME + ".extra.ACTIVITY_OPTIONS"; + public static final String EXTRA_UNSUSPEND_INTENT = PACKAGE_NAME + ".extra.UNSUSPEND_INTENT"; private Intent mMoreDetailsIntent; + private IntentSender mOnUnsuspend; + private String mSuspendedPackage; + private String mSuspendingPackage; + private int mNeutralButtonAction; private int mUserId; private PackageManager mPm; private Resources mSuspendingAppResources; @@ -63,16 +76,15 @@ public class SuspendedAppActivity extends AlertActivity return packageName; } - private Intent getMoreDetailsActivity(String suspendingPackage, String suspendedPackage, - int userId) { + private Intent getMoreDetailsActivity() { final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS) - .setPackage(suspendingPackage); + .setPackage(mSuspendingPackage); final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS; final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent, - MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, userId); + MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, mUserId); if (resolvedInfo != null && resolvedInfo.activityInfo != null && requiredPermission.equals(resolvedInfo.activityInfo.permission)) { - moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage) + moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); return moreDetailsIntent; } @@ -105,8 +117,8 @@ public class SuspendedAppActivity extends AlertActivity return getString(R.string.app_suspended_title); } - private String resolveDialogMessage(String suspendingPkg, String suspendedPkg) { - final CharSequence suspendedAppLabel = getAppLabel(suspendedPkg); + private String resolveDialogMessage() { + final CharSequence suspendedAppLabel = getAppLabel(mSuspendedPackage); if (mSuppliedDialogInfo != null) { final int messageId = mSuppliedDialogInfo.getDialogMessageResId(); final String message = mSuppliedDialogInfo.getDialogMessage(); @@ -122,10 +134,30 @@ public class SuspendedAppActivity extends AlertActivity } } return getString(R.string.app_suspended_default_message, suspendedAppLabel, - getAppLabel(suspendingPkg)); + getAppLabel(mSuspendingPackage)); } + /** + * Returns a text to be displayed on the neutral button or {@code null} if the button should + * not be shown. + */ + @Nullable private String resolveNeutralButtonText() { + final int defaultButtonTextId; + switch (mNeutralButtonAction) { + case BUTTON_ACTION_MORE_DETAILS: + if (mMoreDetailsIntent == null) { + return null; + } + defaultButtonTextId = R.string.app_suspended_more_details; + break; + case BUTTON_ACTION_UNSUSPEND: + defaultButtonTextId = R.string.app_suspended_unsuspend_message; + break; + default: + Slog.w(TAG, "Unknown neutral button action: " + mNeutralButtonAction); + return null; + } final int buttonTextId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getNeutralButtonTextResId() : ID_NULL; if (buttonTextId != ID_NULL && mSuspendingAppResources != null) { @@ -135,7 +167,7 @@ public class SuspendedAppActivity extends AlertActivity Slog.e(TAG, "Could not resolve string resource id " + buttonTextId); } } - return getString(R.string.app_suspended_more_details); + return getString(defaultButtonTextId); } @Override @@ -152,27 +184,29 @@ public class SuspendedAppActivity extends AlertActivity finish(); return; } - final String suspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE); - final String suspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE); + mSuspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE); + mSuspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE); mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO); + mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT); if (mSuppliedDialogInfo != null) { try { - mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(suspendingPackage, + mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(mSuspendingPackage, mUserId); } catch (PackageManager.NameNotFoundException ne) { - Slog.e(TAG, "Could not find resources for " + suspendingPackage, ne); + Slog.e(TAG, "Could not find resources for " + mSuspendingPackage, ne); } } + mNeutralButtonAction = (mSuppliedDialogInfo != null) + ? mSuppliedDialogInfo.getNeutralButtonAction() : BUTTON_ACTION_MORE_DETAILS; + mMoreDetailsIntent = (mNeutralButtonAction == BUTTON_ACTION_MORE_DETAILS) + ? getMoreDetailsActivity() : null; final AlertController.AlertParams ap = mAlertParams; ap.mIcon = resolveIcon(); ap.mTitle = resolveTitle(); - ap.mMessage = resolveDialogMessage(suspendingPackage, suspendedPackage); + ap.mMessage = resolveDialogMessage(); ap.mPositiveButtonText = getString(android.R.string.ok); - mMoreDetailsIntent = getMoreDetailsActivity(suspendingPackage, suspendedPackage, mUserId); - if (mMoreDetailsIntent != null) { - ap.mNeutralButtonText = resolveNeutralButtonText(); - } + ap.mNeutralButtonText = resolveNeutralButtonText(); ap.mPositiveButtonListener = ap.mNeutralButtonListener = this; setupAlert(); } @@ -181,21 +215,62 @@ public class SuspendedAppActivity extends AlertActivity public void onClick(DialogInterface dialog, int which) { switch (which) { case AlertDialog.BUTTON_NEUTRAL: - startActivityAsUser(mMoreDetailsIntent, mOptions, UserHandle.of(mUserId)); - Slog.i(TAG, "Started activity: " + mMoreDetailsIntent.getAction() - + " in user " + mUserId); + switch (mNeutralButtonAction) { + case BUTTON_ACTION_MORE_DETAILS: + if (mMoreDetailsIntent != null) { + startActivityAsUser(mMoreDetailsIntent, mOptions, + UserHandle.of(mUserId)); + } else { + Slog.wtf(TAG, "Neutral button should not have existed!"); + } + break; + case BUTTON_ACTION_UNSUSPEND: + final IPackageManager ipm = AppGlobals.getPackageManager(); + try { + final String[] errored = ipm.setPackagesSuspendedAsUser( + new String[]{mSuspendedPackage}, false, null, null, null, + mSuspendingPackage, mUserId); + if (ArrayUtils.contains(errored, mSuspendedPackage)) { + Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage); + break; + } + } catch (RemoteException re) { + Slog.e(TAG, "Can't talk to system process", re); + break; + } + final Intent reportUnsuspend = new Intent() + .setAction(Intent.ACTION_PACKAGE_UNSUSPENDED_MANUALLY) + .putExtra(Intent.EXTRA_PACKAGE_NAME, mSuspendedPackage) + .setPackage(mSuspendingPackage) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + sendBroadcastAsUser(reportUnsuspend, UserHandle.of(mUserId)); + + if (mOnUnsuspend != null) { + try { + mOnUnsuspend.sendIntent(this, 0, null, null, null); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, "Error while starting intent " + mOnUnsuspend, e); + } + } + break; + default: + Slog.e(TAG, "Unexpected action on neutral button: " + mNeutralButtonAction); + break; + } break; } finish(); } public static Intent createSuspendedAppInterceptIntent(String suspendedPackage, - String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options, int userId) { + String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options, + IntentSender onUnsuspend, int userId) { return new Intent() .setClassName("android", SuspendedAppActivity.class.getName()) .putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage) .putExtra(EXTRA_DIALOG_INFO, dialogInfo) .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage) + .putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend) .putExtra(EXTRA_ACTIVITY_OPTIONS, options) .putExtra(Intent.EXTRA_USER_ID, userId) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java index 86a0d10cf67e..246a07d3d0fe 100644 --- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java +++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java @@ -16,6 +16,7 @@ package com.android.internal.app.chooser; +import android.annotation.Nullable; import android.app.Activity; import android.content.ComponentName; import android.content.Context; @@ -70,7 +71,8 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { public SelectableTargetInfo(Context context, DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget, - float modifiedScore, SelectableTargetInfoCommunicator selectableTargetInfoComunicator) { + float modifiedScore, SelectableTargetInfoCommunicator selectableTargetInfoComunicator, + @Nullable ShortcutInfo shortcutInfo) { mContext = context; mSourceInfo = sourceInfo; mChooserTarget = chooserTarget; @@ -91,7 +93,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { } } // TODO(b/121287224): do this in the background thread, and only for selected targets - mDisplayIcon = getChooserTargetIconDrawable(chooserTarget); + mDisplayIcon = getChooserTargetIconDrawable(chooserTarget, shortcutInfo); if (sourceInfo != null) { mBackupResolveInfo = null; @@ -134,34 +136,18 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { return mIsSuspended; } - /** - * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip - * the call to LauncherApps#getShortcuts(ShortcutQuery). - */ - // TODO(121287224): Refactor code to apply the suggestion above - private Drawable getChooserTargetIconDrawable(ChooserTarget target) { + private Drawable getChooserTargetIconDrawable(ChooserTarget target, + @Nullable ShortcutInfo shortcutInfo) { Drawable directShareIcon = null; // First get the target drawable and associated activity info final Icon icon = target.getIcon(); if (icon != null) { directShareIcon = icon.loadDrawable(mContext); - } else if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) { - Bundle extras = target.getIntentExtras(); - if (extras != null && extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) { - CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID); - LauncherApps launcherApps = (LauncherApps) mContext.getSystemService( - Context.LAUNCHER_APPS_SERVICE); - final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery(); - q.setPackage(target.getComponentName().getPackageName()); - q.setShortcutIds(Arrays.asList(shortcutId.toString())); - q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC); - final List<ShortcutInfo> shortcuts = - launcherApps.getShortcuts(q, mContext.getUser()); - if (shortcuts != null && shortcuts.size() > 0) { - directShareIcon = launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0); - } - } + } else if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS && shortcutInfo != null) { + LauncherApps launcherApps = (LauncherApps) mContext.getSystemService( + Context.LAUNCHER_APPS_SERVICE); + directShareIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, 0); } if (directShareIcon == null) return null; diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index de64573d1e24..b232efc8f46c 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -364,6 +364,12 @@ public final class SystemUiDeviceConfigFlags { */ public static final String NAV_BAR_HANDLE_FORCE_OPAQUE = "nav_bar_handle_force_opaque"; + /** + * (boolean) Whether to force the Nav Bar handle to remain visible over the lockscreen. + */ + public static final String NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN = + "nav_bar_handle_show_over_lockscreen"; + private SystemUiDeviceConfigFlags() { } } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 8412b846b2a6..adb403681b36 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -95,8 +95,6 @@ import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowCallbacks; import android.view.WindowInsets; -import android.view.WindowInsets.Side; -import android.view.WindowInsets.Type; import android.view.WindowInsetsController; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -131,9 +129,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private static final boolean SWEEP_OPEN_MENU = false; // The height of a window which has focus in DIP. - private final static int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; + public static final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; // The height of a window which has not in DIP. - private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5; + public static final int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5; private static final int SCRIM_LIGHT = 0xe6ffffff; // 90% white @@ -1629,7 +1627,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int opacity = PixelFormat.OPAQUE; final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration; - if (winConfig.hasWindowShadow()) { + // If we draw shadows in the compositor we don't need to force the surface to be + // translucent. + if (winConfig.hasWindowShadow() && !mWindow.mRenderShadowsInCompositor) { // If the window has a shadow, it must be translucent. opacity = PixelFormat.TRANSLUCENT; } else{ @@ -2414,6 +2414,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } private void updateElevation() { + // If rendering shadows in the compositor, don't set an elevation on the view + if (mWindow.mRenderShadowsInCompositor) { + return; + } float elevation = 0; final boolean wasAdjustedForStack = mElevationAdjustedForStack; // Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null) diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 95558c31e671..f13a638f7844 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -17,6 +17,7 @@ package com.android.internal.policy; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; +import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR; import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -134,6 +135,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static String TAG = "PhoneWindow"; + /* If true, shadows drawn around the window will be rendered by the system compositor. If + * false, shadows will be drawn by the client by setting an elevation on the root view and + * the contents will be inset by the shadow radius. */ + public final boolean mRenderShadowsInCompositor; + private static final boolean DEBUG = false; private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300; @@ -327,6 +333,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); + mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(), + DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0; } /** diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index aa0ac37b007a..a2736333383e 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -16,6 +16,7 @@ package com.android.internal.statusbar; +import android.app.ITransientNotificationCallback; import android.content.ComponentName; import android.graphics.Rect; import android.hardware.biometrics.IBiometricServiceReceiverInternal; @@ -198,4 +199,15 @@ oneway interface IStatusBar * Dismiss the warning that the device is about to go to sleep due to user inactivity. */ void dismissInattentiveSleepWarning(boolean animated); + + /** + * Displays a text toast. + */ + void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken, + int duration, @nullable ITransientNotificationCallback callback); + + /** + * Cancels toast with token {@code token} in {@code packageName}. + */ + void hideToast(String packageName, IBinder token); } diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index eb7d432b559b..30e914de45c2 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -34,7 +34,6 @@ #include <string> #define DEBUG_PARCEL 0 -#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10)) static jclass gBitmap_class; static jfieldID gBitmap_nativePtr; @@ -587,7 +586,6 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { android::Parcel* p = android::parcelForJavaObject(env, parcel); - const bool isMutable = p->readInt32() != 0; const SkColorType colorType = (SkColorType)p->readInt32(); const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); const uint32_t colorSpaceSize = p->readUint32(); @@ -636,11 +634,10 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the bitmap in place from the ashmem region if possible otherwise copy. sk_sp<Bitmap> nativeBitmap; - if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { + if (blob.fd() >= 0 && !blob.isMutable()) { #if DEBUG_PARCEL - ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " + ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob " "(fds %s)", - isMutable ? "mutable" : "immutable", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif @@ -657,7 +654,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the pixels in place and take ownership of the ashmem region. We must also respect the // rowBytes value already set on the bitmap instead of attempting to compute our own. nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd, - const_cast<void*>(blob.data()), size, !isMutable); + const_cast<void*>(blob.data()), size, true); if (!nativeBitmap) { close(dupFd); blob.release(); @@ -695,7 +692,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } return createBitmap(env, nativeBitmap.release(), - getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); + getPremulBitmapCreateFlags(false), NULL, NULL, density); #else doThrowRE(env, "Cannot use parcels outside of Android"); return NULL; @@ -703,9 +700,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, - jlong bitmapHandle, - jboolean isMutable, jint density, - jobject parcel) { + jlong bitmapHandle, jint density, jobject parcel) { #ifdef __ANDROID__ // Layoutlib does not support parcel if (parcel == NULL) { SkDebugf("------- writeToParcel null parcel\n"); @@ -718,7 +713,6 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); bitmapWrapper->getSkBitmap(&bitmap); - p->writeInt32(isMutable); p->writeInt32(bitmap.colorType()); p->writeInt32(bitmap.alphaType()); SkColorSpace* colorSpace = bitmap.colorSpace(); @@ -745,7 +739,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, // Transfer the underlying ashmem region if we have one and it's immutable. android::status_t status; int fd = bitmapWrapper->bitmap().getAshmemFd(); - if (fd >= 0 && !isMutable && p->allowFds()) { + if (fd >= 0 && p->allowFds()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " "immutable blob (fds %s)", @@ -761,17 +755,14 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, } // Copy the bitmap to a new blob. - bool mutableCopy = isMutable; #if DEBUG_PARCEL - ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", - isMutable ? "mutable" : "immutable", - mutableCopy ? "mutable" : "immutable", + ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); #endif size_t size = bitmap.computeByteSize(); android::Parcel::WritableBlob blob; - status = p->writeBlob(size, mutableCopy, &blob); + status = p->writeBlob(size, false, &blob); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; @@ -1109,7 +1100,7 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeCreateFromParcel", "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", (void*)Bitmap_createFromParcel }, - { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", + { "nativeWriteToParcel", "(JILandroid/os/Parcel;)Z", (void*)Bitmap_writeToParcel }, { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", (void*)Bitmap_extractAlpha }, diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 89dbca816d61..0eb364d40920 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -330,6 +330,22 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin closedir(d); } +void android_os_Process_setProcessFrozen( + JNIEnv *env, jobject clazz, jint pid, jint uid, jboolean freeze) +{ + bool success = true; + + if (freeze) { + success = SetProcessProfiles(uid, pid, {"Frozen"}); + } else { + success = SetProcessProfiles(uid, pid, {"Unfrozen"}); + } + + if (!success) { + signalExceptionForGroupError(env, EINVAL, pid); + } +} + jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid) { SchedPolicy sp; @@ -1327,6 +1343,7 @@ static const JNINativeMethod methods[] = { {"setGid", "(I)I", (void*)android_os_Process_setGid}, {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal}, {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet}, + {"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen}, {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory}, {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory}, {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 126d44529edc..60f2fc8e081f 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -589,7 +589,8 @@ message ServiceRecordProto { repeated IntentBindRecordProto bindings = 25; repeated ConnectionRecordProto connections = 26; - // Next Tag: 27 + optional bool allow_while_in_use_permission_in_fgs = 27; + // Next Tag: 28 } message ConnectionRecordProto { diff --git a/core/proto/android/server/usagestatsservice_v2.proto b/core/proto/android/server/usagestatsservice_v2.proto index a28fcf3589f1..24b0728c29ec 100644 --- a/core/proto/android/server/usagestatsservice_v2.proto +++ b/core/proto/android/server/usagestatsservice_v2.proto @@ -99,6 +99,7 @@ message EventObfuscatedProto { optional int32 instance_id = 10; optional int32 task_root_package_token = 11; optional int32 task_root_class_token = 12; + optional int32 locus_id_token = 13; } /** @@ -117,6 +118,7 @@ message PendingEventProto { optional int32 instance_id = 10; optional string task_root_package = 11; optional string task_root_class = 12; + optional string locus_id = 13; } /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4595bab82465..020a8352ad07 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -53,6 +53,7 @@ <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" /> <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" /> <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" /> + <protected-broadcast android:name="android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY" /> <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" /> <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" /> <protected-broadcast android:name="android.intent.action.UID_REMOVED" /> @@ -93,7 +94,6 @@ <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" /> <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" /> <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" /> - <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" /> <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" /> <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" /> @@ -1528,6 +1528,14 @@ android:protectionLevel="signature|privileged" /> <uses-permission android:name="android.permission.LOCATION_HARDWARE"/> + <!-- @SystemApi Allows an application to use the Context Hub. + <p>Not for use by third-party applications. + @hide + --> + <permission android:name="android.permission.ACCESS_CONTEXT_HUB" + android:protectionLevel="signature" /> + <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/> + <!-- @SystemApi Allows an application to create mock location providers for testing. <p>Protection level: signature @hide @@ -4298,6 +4306,11 @@ <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" android:protectionLevel="signature" /> + <!-- Allows applications to set the initial lockscreen state. + <p>Not for use by third-party applications. @hide --> + <permission android:name="android.permission.SET_INITIAL_LOCK" + android:protectionLevel="signature|setup"/> + <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_FINGERPRINT" android:protectionLevel="signature|privileged" /> @@ -5046,12 +5059,6 @@ android:process=":ui"> </activity> - <activity android:name="com.android.internal.app.BlockedAppActivity" - android:theme="@style/Theme.Dialog.Confirmation" - android:excludeFromRecents="true" - android:process=":ui"> - </activity> - <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity" android:theme="@style/Theme.Dialog.Confirmation" android:excludeFromRecents="true"> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index be0e58824ad8..de8f55bb8036 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ek"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-opsies"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-opsies"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"by jou kalender in te gaan"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS-boodskappe te stuur en te bekyk"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Lêers en media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"toegang te verkry tot foto\'s, media en lêers op jou toestel"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofoon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"oudio op te neem"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tik, swiep, knyp en ander gebare uitvoer."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Vingerafdrukgebare"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan gebare vasvang wat op die toestel se vingerafdruksensor uitgevoer word."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Neem skermkiekie"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Kan \'n skermkiekie neem."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"deaktiveer of verander statusbalk"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Laat die program toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"wees die statusbalk"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word.\n\n Bestaande toeganklikheidkenmerk:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Jy kan die kenmerk in Instellings > Toeganklikheid verander."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Maak leeg"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Wysig kortpaaie"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselleer"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Skakel kortpad af"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Program is nie beskikbaar nie"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nie nou onmiddellik beskikbaar nie. Dit word bestuur deur <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Kom meer te wete"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Skakel werkprofiel aan?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jou werkprogramme, kennisgewings, data en ander werkprofielkenmerke sal aangeskakel word"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Hierdie program is vir \'n ouer weergawe van Android gebou en sal dalk nie behoorlik werk nie. Probeer kyk vir opdaterings, of kontak die ontwikkelaar."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kyk vir opdatering"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Jy het nuwe boodskappe"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery kan afloop voordat dit normaalweg gelaai word"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterybespaarder"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterybespaarder is afgeskakel"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Foon se battery het genoeg krag. Kenmerke is nie meer beperk nie."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tablet se battery het genoeg krag. Kenmerke is nie meer beperk nie."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Toestel se battery het genoeg krag. Kenmerke is nie meer beperk nie."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Vouer"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-program"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Lêer"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-sigblad"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Aanbieding"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-aanbieding"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth sal tydens vliegtuigmodus aan bly"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Laai tans"</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> lêers</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Wissel verdeelde skerm"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index c92d3b0b6947..ec9abfe3e67f 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string> <string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"እኔ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"የጡባዊ አማራጮች"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV አማራጮች"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"የተደራሽነት አቋራጭ ጥቅም ላይ ይዋል?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"አቋራጩ ሲበራ ሁለቱንም የድምፅ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።\n\n አሁን ያለ የተደራሽነት ባህሪ፦\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ባህሪውን በቅንብሮች > ተደራሽነት ውስጥ ሊለውጡት ይችላሉ።"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ባዶ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"አቋራጮችን አርትዕ ያድርጉ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ይቅር"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"አቋራጩን አጥፋ"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"መተግበሪያ አይገኝም"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> አሁን ላይ አይገኝም። በ<xliff:g id="APP_NAME_1">%2$s</xliff:g> የሚተዳደር ነው።"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"የበለጠ ለመረዳት"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"የስራ መገለጫ ይብራ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"የእርስዎ የስራ መተግበሪያዎች፣ ማሳወቂያዎች፣ ውሂብ እና ሌሎች የስራ መገለጫ ባህሪያት ይበራሉ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"አብራ"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ይህ መተግበሪያ ለቆየ የAndroid ስሪት ነው የተገነባው፣ እና በአግባቡ ላይሰራ ይችላል። ዝማኔዎች ካሉ ለመመልከት ይሞክሩ፣ ወይም ደግሞ ገንቢውን ያነጋግሩ።"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ዝማኔ ካለ አረጋግጥ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"አዲስ መልዕክቶች አለዎት"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"የ<xliff:g id="EXTENSION">%1$s</xliff:g> ተመን ሉህ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"የዝግጅት አቀራረብ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"የ<xliff:g id="EXTENSION">%1$s</xliff:g> ዝግጅት አቀራረብ"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ብሉቱዝ በአውሮፕላን ሁነታ ጊዜ እንደበራ ይቆያል"</string> <string name="car_loading_profile" msgid="8219978381196748070">"በመጫን ላይ"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ፋይሎች</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"የተከፈለ ማያን ቀያይር"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 1a6bbd8dc9a3..0d70a11f2eeb 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -49,7 +49,7 @@ <string name="invalidPuk" msgid="8831151490931907083">"اكتب رمز PUK مكونًا من ٨ أرقام أو أكثر."</string> <string name="needPuk" msgid="7321876090152422918">"شريحة SIM مؤمّنة برمز PUK. اكتب رمز PUK لإلغاء تأمينها."</string> <string name="needPuk2" msgid="7032612093451537186">"اكتب PUK2 لإلغاء تأمين شريحة SIM."</string> - <string name="enablePin" msgid="2543771964137091212">"محاولة غير ناجحة، مكّن قفل SIM/RUIM."</string> + <string name="enablePin" msgid="2543771964137091212">"محاولة غير ناجحة، فعّل قفل SIM/RUIM."</string> <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584"> <item quantity="zero">لم يتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item> <item quantity="two">يتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدهما قفل شريحة SIM.</item> @@ -202,6 +202,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string> <string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"أنا"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"خيارات الجهاز اللوحي"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"خيارات Android TV"</string> @@ -299,8 +303,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"الوصول تقويمك"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"إرسال رسائل قصيرة SMS وعرضها"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"الملفات والوسائط"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"الوصول إلى الصور والوسائط والملفات على جهازك"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"الميكروفون"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"تسجيل الصوت"</string> @@ -326,10 +329,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"يمكن النقر والتمرير بسرعة والتصغير أو التكبير بإصبعين وتنفيذ إيماءات أخرى."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"إيماءات بصمات الإصبع"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"يمكن أن تلتقط الإيماءات التي تم تنفيذها على جهاز استشعار بصمات الإصبع في الجهاز."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"أخذ لقطة شاشة"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"يمكن أخذ لقطة شاشة."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"إيقاف شريط الحالة أو تعديله"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"للسماح للتطبيق بإيقاف شريط الحالة أو إضافة رموز نظام وإزالتها."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"العمل كشريط للحالة"</string> @@ -606,7 +607,7 @@ <string name="permlab_readSyncSettings" msgid="6250532864893156277">"قراءة إعدادات المزامنة"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string> <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"التبديل بين تشغيل المزامنة وإيقافها"</string> - <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"للسماح للتطبيق بتعديل إعدادات المزامنة لحساب ما. على سبيل المثال، يمكن استخدام ذلك لتمكين مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string> + <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"للسماح للتطبيق بتعديل إعدادات المزامنة لحساب ما. على سبيل المثال، يمكن استخدام ذلك لتفعيل مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string> <string name="permlab_readSyncStats" msgid="3747407238320105332">"قراءة إحصاءات المزامنة"</string> <string name="permdesc_readSyncStats" msgid="3867809926567379434">"للسماح للتطبيق بقراءة إحصائيات المزامنة لحساب ما، بما في ذلك سجل الأحداث المتزامنة ومقدار البيانات التي تمت مزامنتها."</string> <string name="permlab_sdcardRead" msgid="5791467020950064920">"قراءة محتوى مساحة التخزين المشتركة"</string> @@ -1703,7 +1704,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"هل تريد استخدام اختصار \"سهولة الاستخدام\"؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"عند تشغيل الاختصار، يؤدي الضغط على زرّي مستوى الصوت لمدة 3 ثوانٍ إلى تفعيل ميزة \"سهولة الاستخدام\".\n\n ميزة \"سهولة الاستخدام\" الحالية:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n يمكنك تغيير الميزة من \"الإعدادات\" > \"سهولة الاستخدام\"."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"فارغ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"تعديل الاختصارات"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"إلغاء"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"إيقاف الاختصار"</string> @@ -1978,13 +1978,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"التطبيق غير متاح"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"التطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> غير متاح الآن، وهو مُدار بواسطة <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"مزيد من المعلومات"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"تفعيل الملف الشخصي للعمل؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"تشغيل"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"تمّ إنشاء هذا التطبيق لإصدار قديم من Android وقد لا يعمل بشكل صحيح. جرِّب البحث عن تحديثات أو الاتصال بمطوّر البرامج."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن تحديث"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"لديك رسائل جديدة"</string> @@ -2099,14 +2097,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"تم شحن الجهاز بدرجة كافية وتفعيل الميزات مرة أخرى"</string> <string name="mime_type_folder" msgid="2203536499348787650">"مجلّد"</string> <string name="mime_type_apk" msgid="3168784749499623902">"تطبيق Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ملف"</string> @@ -2125,6 +2119,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"جدول بيانات: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"عرض تقديمي"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"عرض تقديمي: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"سيظل البلوتوث مفعَّلاً أثناء تفعيل \"وضع الطائرة\"."</string> <string name="car_loading_profile" msgid="8219978381196748070">"جارٍ التحميل"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="zero"><xliff:g id="FILE_NAME_2">%s</xliff:g> و<xliff:g id="COUNT_3">%d</xliff:g> ملف</item> @@ -2146,5 +2141,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تبديل \"تقسيم الشاشة\""</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index faa99a2aa7cd..ad11a37524a0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string> <string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"মই"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"টে\'বলেটৰ বিকল্পসমূহ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVৰ বিকল্পসমূহ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"আপোনাৰ কেলেণ্ডাৰ ব্যৱহাৰ কৰিব পাৰে"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"এছএমএছ"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"এছএমএছ বার্তা পঠিয়াব আৰু চাব পাৰে"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ফাইল আৰু মিডিয়াবোৰ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"আপোনাৰ ডিভাইচৰ ফট\', মিডিয়া আৰু ফাইলসমূহ ব্যৱহাৰ কৰিব পাৰে"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"মাইক্ৰ\'ফ\'ন"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"অডিঅ\' ৰেকর্ড কৰিব পাৰে"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"টেপ কৰা, ছোৱাইপ কৰা, পিঞ্চ কৰা আৰু আঙুলিৰ স্পৰ্শেৰে নিৰ্দেশ কৰা অন্যান্য কাৰ্যসমূহ কৰিব পাৰে।"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ফিংগাৰপ্ৰিণ্ট নিৰ্দেশ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ডিভাইচটোৰ ফিংগাৰপ্ৰিণ্ট ছেন্সৰত দিয়া নিৰ্দেশ বুজিব পাৰে।"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"স্ক্ৰীনশ্বট লওক"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ডিছপ্লে’খনৰ এটা স্ক্ৰীনশ্বট ল\'ব পাৰে।"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"স্থিতি দণ্ড অক্ষম কৰক বা সলনি কৰক"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"স্থিতি দণ্ড অক্ষম কৰিবলৈ বা ছিষ্টেম আইকন আঁতৰাবলৈ এপটোক অনুমতি দিয়ে।"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"স্থিতি দণ্ড হ\'ব পাৰে"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"শ্বৰ্টকাট অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটামত ৩ ছেকেণ্ডৰ বাবে ছাপ দি থাকিলে দিব্যাংগসকলৰ বাবে থকা সুবিধা এটা আৰম্ভ হ\'ব। \n\n চলিত দিব্যাংগসকলৰ সুবিধা:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপুনি এই সুবিধাটো ছেটিংসমূহ > দিব্যাংগসকলৰ বাবে সুবিধা-লৈ গৈ সলনি কৰিব পাৰে।"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"খালী কৰক"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শ্বৰ্টকাটসমূহ সম্পাদনা কৰক"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল কৰক"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শ্বৰ্টকাট অফ কৰক"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"এপটো নাই"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"অধিক জানক"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"কৰ্মস্থানৰ প্ৰ\'ফাইল অন কৰিবনে?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"আপোনাৰ কৰ্মস্থানৰ এপসমূহ, জাননীসমূহ, ডেটা আৰু কৰ্মস্থানৰ প্ৰ\'ফাইলৰ অইন সুবিধাসমূহ অন কৰা হ\'ব"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই এপটো Androidৰ এটা পুৰণা সংস্কৰণৰ বাবে প্ৰস্তুত কৰা হৈছিল, আৰু ই বিচৰাধৰণে কাম নকৰিবও পাৰে। ইয়াৰ আপডে’ট আছে নেকি চাওক, বা বিকাশকৰ্তাৰ সৈতে যোগাযোগ কৰক।"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডে’ট আছে নেকি চাওক"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"আপুনি নতুন বার্তা লাভ কৰিছে"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ডিভাইচটোত পর্যাপ্ত পৰিমাণে চার্জ আছে। সুবিধাবোৰ আৰু সীমাবদ্ধ কৰা নাই।"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ফ’ল্ডাৰ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android এপ্লিকেশ্বন"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ফাইল"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> স্প্ৰেডশ্বীট"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"উপস্থাপন"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> উপস্থাপন"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"এয়াৰপ্লেন ম\'ডৰ সময়ত ব্লুটুথ অন হৈ থাকিব"</string> <string name="car_loading_profile" msgid="8219978381196748070">"ল’ড হৈ আছে"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g>টা ফাইল</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"বিভাজিত স্ক্ৰীন ট’গল কৰক"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index d97b73f79a67..a535f1f0e2ba 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mən"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planşet seçimləri"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçimləri"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"təqvimə daxil olun"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"göndərin və SMS mesajlarına baxın"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Fayllar və media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"cihazınızda foto, media və fayllara daxil olun"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"səsi qeydə alın"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Digər jestlərə tıklaya, sürüşdürə və əməliyyat apara bilərsiniz."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Barmaq izi işarələri"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Cihazların barmaq izi sensorunda olan işarələri əldə edə bilər."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ekran şəkli çəkin"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Ekran şəkli çəkilə bilər."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"status panelini deaktivləşdir və ya dəyişdir"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Tətbiqə status panelini deaktiv etməyə və ya sistem ikonalarını əlavə etmək və ya silmək imkanı verir."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"status paneli edin"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Qısayol aktiv olduqda hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası işə başlayacaq.\n\n Cari əlçatımlılıq funksiyası:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funksiyanı Ayarlar və Əçatımlılıq bölməsində dəyişə bilərsiniz."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Boşaldın"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ləğv edin"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Qısayolu Deaktiv edin"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Tətbiq əlçatmazdır"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hazırda əlçatan deyil. Bunu <xliff:g id="APP_NAME_1">%2$s</xliff:g> idarə edir."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ətraflı məlumat"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"İş profili aktiv edilsin?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"İş tətbiqləri, bildirişləri, data və digər iş profili funksiyaları aktiv ediləcək"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu tətbiq köhnə Android versiyası üçün hazırlanıb və düzgün işləməyə bilər. Güncəlləməni yoxlayın və ya developer ilə əlaqə saxlayın."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncəlləməni yoxlayın"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Enerjiyə qənaət"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Enerjiyə qənaət deaktivdir"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonun kifayət qədər enerjisi var. Funksiyalar artıq məhdud deyil."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Planşetin kifayət qədər enerjisi var. Funksiyalar artıq məhdud deyil."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Cihazın kifayət qədər enerjisi var. Funksiyalar artıq məhdud deyil."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Qovluq"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android tətbiqi"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fayl"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> cədvəl"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Təqdimat"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> təqdimat"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth təyyarə rejimində aktiv olacaq"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Yüklənir"</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> fayl</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekrana keçid"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index c37e2b436393..249e5af2d585 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije za tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string> @@ -1634,7 +1638,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti.\n\n Aktuelna funkcija pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Možete da promenite funkciju u odeljku Podešavanja > Pristupačnost."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prazno"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Izmenite prečice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string> @@ -1879,11 +1882,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. <xliff:g id="APP_NAME_1">%2$s</xliff:g> upravlja dostupnošću."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo profil za Work?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije profila za Work"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je napravljena za stariju verziju Android-a, pa možda neće raditi ispravno. Potražite ažuriranja ili kontaktirajte programera."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Potraži ažuriranje"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string> @@ -2017,6 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> tabela"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacija"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentacija"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth ostaje uključen tokom režima rada u avionu"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Učitava se"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> i još <xliff:g id="COUNT_3">%d</xliff:g> datoteka</item> @@ -2035,5 +2039,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite/isključite podeljeni ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 855ce25ad3d1..dc4c56e684ee 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Параметры планшэта"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Параметры Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"атрымліваць доступ да вашага календара"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"адпраўляць і праглядаць SMS-паведамленні"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы і мультымедыя"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"атрымліваць доступ да фатаграфій, медыяфайлаў і файлаў на вашай прыладзе"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Мікрафон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"запісваць аўдыя"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Можна кранаць, праводзіць пальцам, маштабаваць шчыпком, а таксама выконваць іншыя жэсты."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Жэсты на сканеры адбіткаў пальцаў"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Можа распазнаваць жэсты на сканеры адбіткаў пальцаў прылады."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Зрабіць здымак экрана"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Можна зрабіць здымак экрана."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"адключаць ці змяняць радок стану"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"быць панэллю стану"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Калі камбінацыя хуткага доступу ўключана, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб уключыць функцыю спецыяльных магчымасцей.\n\n Бягучая функцыя спецыяльных магчымасцей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Вы можаце змяніць гэту функцыю ў меню \"Налады > Спецыяльныя магчымасці\"."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Пуста"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змяніць ярлыкі"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасаваць"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Дэактываваць камбінацыю хуткага доступу"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Праграма недаступная"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" цяпер недаступная. Яна кіруецца праграмай \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Даведацца больш"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Уключыць працоўны профіль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Будуць уключаны вашы рабочыя праграмы, апавяшчэнні, даныя і іншыя функцыі працоўнага профілю"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Уключыць"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Гэта праграма была створана для больш старой версіі Android і можа не працаваць належным чынам. Праверце наяўнасць абнаўленняў або звярніцеся да распрацоўшчыка."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Праверыць на наяўнасць абнаўленняў"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"У вас ёсць новыя паведамленні"</string> @@ -2033,14 +2031,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"У прылады дастатковы ўзровень зараду. Функцыі больш не абмежаваны."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Папка"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Праграма Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Табліца <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Прэзентацыя"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Прэзентацыя <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth застанецца ўключаным у рэжыме палёту"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Загрузка"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> файл</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Пераключальнік падзеленага экрана"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 40e20d3ea2e0..30b7d302a273 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Аз"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции за таблета"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции за Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Искате ли да използвате пряк път към функцията за достъпност?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за промяна на силата на звука и ги задържите 3 секунди.\n\n Текущата функция за достъпност е:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцията от „Настройки“ > „Достъпност“."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Празно"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редактиране на преките пътища"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отказ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Изключване на прекия път"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Няма достъп до приложението"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"В момента няма достъп до <xliff:g id="APP_NAME_0">%1$s</xliff:g>. Това се управлява от <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Научете повече"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Вкл. на служ. потр. профил?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Служебните ви приложения, известия и данни, както и другите функции на служебния потребителски профил ще бъдат включени"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Включване"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string> - <string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Това приложение бе създадено за по-стара версия на Android и може да не работи правилно. Опитайте да проверите за актуализации или се свържете с програмиста."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за актуализация"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови съобщения"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Електронна таблица във формат <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентация"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Презентация във формат <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Функцията за Bluetooth ще остане включена по време на самолетния режим"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Зарежда се"</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> файла</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Превключване на разделения екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 3164bb68d42f..d85b5d6ee716 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string> <string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"আমাকে"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ট্যাবলেট বিকল্পগুলি"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-র বিকল্প"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"এসএমএসগুলি পাঠাতে এবং দেখতে"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ফাইল এবং মিডিয়া"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"আপনার ডিভাইসে ফটো, মিডিয়া এবং ফাইলগুলিতে অ্যাক্সেস"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"মাইক্রোফোন"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"অডিও রেকর্ড"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"আলতো চাপ দেওয়া, সোয়াইপ, পিঞ্চ করা এবং অন্যান্য ইঙ্গিতের কাজগুলি সম্পাদন করতে পারবেন৷"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"আঙ্গুলের ছাপ সেন্সরের উপর করা জেসচার"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ডিভাইসের আঙ্গুলের ছাপের সেন্সরের উপরে ইঙ্গিত করলে বুঝতে পারে।"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"স্ক্রিনশট নিন"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ডিসপ্লের একটি স্ক্রিনশট নিতে পারেন।"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"স্ট্যাটাস বার নিষ্ক্রিয় অথবা সংশোধন করে"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"অ্যাপ্লিকেশনকে স্ট্যাটাস বার অক্ষম করতে এবং সিস্টেম আইকনগুলি সরাতে দেয়৷"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"স্থিতি দন্ডে থাকুন"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"অ্যাক্সেসযোগ্যতা শর্টকাট ব্যবহার করবেন?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"শর্টকাটটি চালু থাকলে দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি বৈশিষ্ট্য চালু হবে।\n\n বর্তমান অ্যাকসেসিবিলিটি বৈশিষ্ট্য:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপনি এই বৈশিষ্ট্যটি সেটিংস > অ্যাকসেসিবিলিটিতে গিয়ে পরিবর্তন করতে পারবেন।"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"খালি"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শর্টকাট এডিট করুন"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল করুন"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শর্টকাট বন্ধ করুন"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"অ্যাপটি উপলভ্য নয়"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> এখন উপলভ্য নয়। এই অ্যাপটিকে <xliff:g id="APP_NAME_1">%2$s</xliff:g> অ্যাপ ম্যানেজ করে।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"আরও জানুন"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"কাজের প্রোফাইল চালু করবেন?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"আপনার কাজের অ্যাপ, বিজ্ঞপ্তি, ডেটা এবং কাজের প্রোফাইলের অন্যান্য বৈশিষ্ট্য চালু করা হবে"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"এই অ্যাপটি Android এর একটি পুরনো ভার্সনের জন্য তৈরি করা হয়েছিল, তাই এখানে সেটি ঠিকমতো কাজ নাও করতে পারে। আপডেট পাওয়া যাচ্ছে কিনা দেখুন বা ডেভেলপারের সাথে যোগাযোগ করুন।"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"আপডেট পাওয়া যাচ্ছে কিনা দেখুন"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"আপনার নতুন মেসেজ আছে"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ডিভাইসের ব্যাটারিতে যথেষ্ট পরিমাণে চার্জ আছে। ফিচারগুলির উপর আর বিধিনিষেধ নেই।"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ফোল্ডার"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android অ্যাপ্লিকেশন"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ফাইল"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> স্প্রেডশীট"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"উপস্থাপনা"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> উপস্থাপনা"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ব্লুটুথ বিমান মোডে চালু থাকবে"</string> <string name="car_loading_profile" msgid="8219978381196748070">"লোড হচ্ছে"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> এবং আরও <xliff:g id="COUNT_3">%d</xliff:g>টি ফাইল</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"স্প্লিট স্ক্রিন টগল করুন"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index e0a48869b16c..c8c65bb15eb0 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tableta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV uređaja"</string> @@ -1636,7 +1640,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritiskom na oba dugmeta za podešavanje jačine zvuka u trajanju od 3 sekunde pokrenut će se funkcija za pristupačnost.\n\n Trenutna funkcija za pristupačnost je:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciju možete promijeniti ako odete u Postavke > Pristupačnost."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prazno"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string> @@ -1881,11 +1884,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. Ovim upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Uključiti radni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se poslovne aplikacije, obavještenja, podaci i druge funkcije radnog profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova aplikacija je pravljena za stariju verziju Androida i možda neće ispravno raditi. Provjerite jesu li dostupna ažuriranja ili kontaktirajte programera."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri je li dostupno ažuriranje"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string> @@ -2019,6 +2022,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> tabela"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacija"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentacija"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen i u načinu rada u avionu"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Učitavanje"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fajl</item> @@ -2037,5 +2041,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključi/isključi podijeljeni ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 93a60d895e8f..42bebe16a004 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcions de la tauleta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcions d\'Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si la drecera està activada, prem els dos botons de volum durant 3 segons, per iniciar una funció d\'accessibilitat.\n\n Funció d\'accessibilitat actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pots canviar la funció a Configuració > Accessibilitat."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Buida"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edita les dreceres"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel·la"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactiva la drecera"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"L\'aplicació no està disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no està disponible en aquests moments. Aquesta opció es gestiona a <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Més informació"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Activar el perfil professional?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions per a la feina, les notificacions, les dades i altres funcions del perfil professional"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tens missatges nous"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Full de càlcul <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentació"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentació <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"El Bluetooth es mantindrà activat durant el mode d\'avió"</string> <string name="car_loading_profile" msgid="8219978381196748070">"S\'està carregant"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> i <xliff:g id="COUNT_3">%d</xliff:g> fitxers més</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Commuta Pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 81b1ebb55c51..2c162914274b 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Já"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zařízení Android TV"</string> @@ -1656,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti.\n\n Aktuální funkce přístupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkci můžete změnit v Nastavení > Přístupnost."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prázdné"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upravit zkratky"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušit"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnout zkratku"</string> @@ -1911,11 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikace není k dispozici"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> momentálně není dostupná. Tato předvolba se spravuje v aplikaci <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Další informace"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Zapnout pracovní profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vaše pracovní aplikace, oznámení, data a ostatní funkce pracovního účtu budou zapnuty"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tato aplikace byla vytvořena pro starší verzi systému Android a nemusí fungovat správně. Zkuste vyhledat aktualizace, případně kontaktujte vývojáře."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Zkontrolovat aktualizace"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové zprávy"</string> @@ -2050,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Tabulka <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentace"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Prezentace <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth v režimu Letadlo zůstane zapnuté"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Načítání"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="few"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> soubory</item> @@ -2069,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Přepnout rozdělenou obrazovku"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 4374b22224ed..f86db77184e6 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mig"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valgmuligheder for tabletcomputeren"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Valgmuligheder for Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"have adgang til din kalender"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Sms"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"sende og se sms-beskeder"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Filer og medier"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"få adgang til billeder, medier og filer på din enhed"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"optage lyd"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Fingeraftryksbevægelser"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan registrere bevægelser, der foretages på enhedens fingeraftrykslæser."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Tag screenshot"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Kan tage et screenshot af skærmen."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"deaktivere eller redigere statuslinje"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Tillader, at appen kan deaktivere statusbjælken eller tilføje og fjerne systemikoner."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"vær statusbjælken"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger > Hjælpefunktioner."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Tom"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediger genveje"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuller"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Deaktiver genvej"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgængelig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Få flere oplysninger"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Skal arbejdsprofilen slås til?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Søg efter opdatering"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye beskeder"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterisparefunktion"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterisparefunktion blev slået fra"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonen har tilstrækkeligt batteri. Funktionerne er ikke længere begrænsede."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tabletten har tilstrækkeligt batteri. Funktionerne er ikke længere begrænsede."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Enheden har tilstrækkeligt batteri. Funktionerne er ikke længere begrænsede."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Mappe"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-app"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fil"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-regneark"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Præsentation"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-præsentation"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth forbliver aktiveret i flytilstand"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Indlæser"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fil</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå Opdelt skærm til eller fra"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 7804e9e1c127..d6a9a010d9da 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eigene"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-Optionen"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-Optionen"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"auf deinen Kalender zugreifen"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS senden und abrufen"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Dateien und Medien"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"auf Fotos, Medien und Dateien auf deinem Gerät zugreifen"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"Audio aufnehmen"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Fingerabdrucksensor-Gesten"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot erstellen"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Es kann ein Screenshot des Displays erstellt werden."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"Statusleiste deaktivieren oder ändern"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"Statusleiste darstellen"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten.\n\n Aktuelle Bedienungshilfe:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kannst die Bedienungshilfe unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Leeren"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Verknüpfungen bearbeiten"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Abbrechen"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Verknüpfung deaktivieren"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App nicht verfügbar"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ist momentan nicht verfügbar. Dies wird über die App \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\" verwaltet."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Weitere Informationen"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Arbeitsprofil aktivieren?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Deine geschäftlichen Apps, Benachrichtigungen, Daten und andere Funktionen des Arbeitsprofils werden aktiviert"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Diese App wurde für eine ältere Android-Version entwickelt und funktioniert möglicherweise nicht mehr richtig. Prüfe, ob Updates verfügbar sind oder kontaktiere den Entwickler."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Auf Updates prüfen"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Du hast neue Nachrichten"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Energiesparmodus"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Energiesparmodus deaktiviert"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Das Smartphone ist ausreichend geladen. Es sind keine Funktionen mehr beschränkt."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Das Tablet ist ausreichend geladen. Es sind keine Funktionen mehr beschränkt."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Das Gerät ist ausreichend geladen. Es sind keine Funktionen mehr beschränkt."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Ordner"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-App"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Datei"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Tabelle (<xliff:g id="EXTENSION">%1$s</xliff:g>)"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Präsentation"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Präsentation (<xliff:g id="EXTENSION">%1$s</xliff:g>)"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth bleibt im Flugmodus aktiviert"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Wird geladen"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> und <xliff:g id="COUNT_3">%d</xliff:g> Dateien</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"\"Bildschirm teilen\" ein-/ausschalten"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sperrbildschirm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index a5977ee082d3..67285e9b0bf3 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Για εμένα"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Επιλογές tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Επιλογές Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Να χρησιμοποιείται η συντόμευση προσβασιμότητας;"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας.\n\n Τρέχουσα λειτουργία προσβασιμότητας:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Μπορείτε να αλλάξετε τη λειτουργία από τις Ρυθμίσεις > Προσβασιμότητα."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Κενό"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Επεξεργασία συντομεύσεων"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Άκυρο"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Απενεργοποίηση συντόμευσης"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Η εφαρμογή δεν είναι διαθέσιμη"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή. Η διαχείριση πραγματοποιείται από την εφαρμογή <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Μάθετε περισσότερα"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ενεργοποίηση προφίλ εργασίας;"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Οι εφαρμογές, οι ειδοποιήσεις και τα δεδομένα εργασίας σας, καθώς και άλλες λειτουργίες του προφίλ εργασίας, θα ενεργοποιηθούν"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ενεργοποίηση"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Αυτή η εφαρμογή δημιουργήθηκε για παλαιότερη έκδοση του Android και μπορεί να μην λειτουργεί σωστά. Δοκιμάστε να ελέγξετε εάν υπάρχουν ενημερώσεις ή επικοινωνήστε με τον προγραμματιστή."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Έλεγχος για ενημέρωση"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Έχετε νέα μηνύματα"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Υπολογιστικό φύλλο <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Παρουσίαση"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Παρουσίαση <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Το Bluetooth θα παραμείνει ενεργό κατά τη λειτουργία πτήσης."</string> <string name="car_loading_profile" msgid="8219978381196748070">"Φόρτωση"</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> αρχεία</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Εναλλαγή διαχωρισμού οθόνης"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index da897933675e..ed31c2274696 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Empty"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string> @@ -1984,6 +1987,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 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> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 560c4cd13061..6ae46b4c646e 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Empty"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string> @@ -1984,6 +1987,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 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> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index da897933675e..ed31c2274696 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Empty"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string> @@ -1984,6 +1987,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 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> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index da897933675e..ed31c2274696 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Empty"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates or contact the developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string> @@ -1984,6 +1987,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 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> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index f7da05ec2a7a..07cb6c7f1c7c 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Me"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Empty"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Turn off Shortcut"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available right now. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data, and other work profile features will be turned on"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Check for update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"You have new messages"</string> @@ -1984,6 +1987,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 during airplane 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> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index aeec9f8dc446..6f83551eca5a 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Yo"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones de tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cuando el acceso directo está activado, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Configuración > Accesibilidad."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Vacío"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"La app no está disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Se activaran las apps de trabajo, los datos, las notificaciones y otras funciones del perfil de trabajo"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta app se creó para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o comunícate con el programador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Hoja de cálculo <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentación"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"La conexión Bluetooth permanecerá activa durante el modo de avión"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> y <xliff:g id="COUNT_3">%d</xliff:g> archivos más</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 1ef891acffb5..737a83b4dbfe 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Yo"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones del tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si el acceso directo está activado, pulsa los dos botones de volumen durante tres segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Ajustes > Accesibilidad."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Vacío"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"La aplicación no está disponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Tus aplicaciones, notificaciones, datos y otras funciones del perfil de trabajo se activarán"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string> - <string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación se ha diseñado para una versión anterior de Android y es posible que no funcione correctamente. Busca actualizaciones o ponte en contacto con el desarrollador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualizaciones"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tienes mensajes nuevos"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Hoja de cálculo <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentación"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"El Bluetooth seguirá activado en el modo avión"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> y <xliff:g id="COUNT_3">%d</xliff:g> archivos</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar la pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 9a4b6d376bf2..021985f50e59 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mina"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tahvelarvuti valikud"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV valikud"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"juurdepääs kalendrile"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"saata ja vaadata SMS-sõnumeid"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Failid ja meedia"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"juurdepääs seadmesse salvestatud fotodele, meediasisule ja failidele"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"heli salvestamine"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Saate puudutada, pühkida, sõrmi kokku-lahku liigutada ja teisi liigutusi teha."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Sõrmejälje liigutused"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Teil on võimalik jäädvustada seadme sõrmejäljeanduril tehtud liigutused."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Jäädvusta ekraanipilt"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Saab jäädvustada ekraanipildi."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"keela või muuda olekuriba"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Võimaldab rakendusel keelata olekuriba või lisada ja eemaldada süsteemiikoone."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"olekuribana kuvamine"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni.\n\n Praegune juurdepääsetavuse funktsioon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Saate seda funktsiooni muuta valikutega Seaded > Juurdepääsetavus."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Tühi"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muuda otseteid"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Tühista"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Lülita otsetee välja"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Rakendus pole saadaval"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pole praegu saadaval. Seda haldab rakendus <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lisateave"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Kas lülitada tööprofiil sisse?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Teie töörakendused, märguanded, andmed ja muud tööprofiili funktsioonid lülitatakse sisse"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"See rakendus on loodud Androidi vanema versiooni jaoks ega pruugi õigesti töötada. Otsige värskendusi või võtke ühendust arendajaga."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Otsi värskendust"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Teile on uusi sõnumeid"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Aku võib enne tavapärast laadimist tühjaks saada"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akusäästja aktiveeriti aku tööea pikendamiseks"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akusäästja"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akusäästja on välja lülitatud"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon on piisavalt laetud. Funktsioonid ei ole enam piiratud."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tahvelarvuti on piisavalt laetud. Funktsioonid ei ole enam piiratud."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Seade on piisavalt laetud. Funktsioonid ei ole enam piiratud."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Kaust"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Androidi rakendus"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fail"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-arvutustabelifail"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Esitlus"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-esitlusefail"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth jääb lennukirežiimi ajal sisselülitatuks"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Laadimine"</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> faili</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Vaheta jagatud ekraanikuva"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index f0a0010cc584..8ecdd0765a67 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ni"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV gailuaren aukerak"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"atzitu egutegia"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS mezuak"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"bidali eta ikusi SMS mezuak"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Fitxategiak eta multimedia-edukia"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"atzitu gailuko argazkiak, multimedia-edukia eta fitxategiak"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofonoa"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"grabatu audioa"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Hatz-marken keinuak"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Gailuaren hatz-marken sentsorean egindako keinuak atzeman ditzake."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Atera pantaila-argazki bat"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Pantaila-argazkiak atera ditzake."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"desgaitu edo aldatu egoera-barra"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"bihurtu egoera-barra"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea.\n\n Uneko erabilerraztasun-eginbidea:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Eginbidea aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Hustu"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editatu lasterbideak"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Utzi"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desaktibatu lasterbidea"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikazioa ez dago erabilgarri"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ez dago erabilgarri une honetan. Haren erabilgarritasuna <xliff:g id="APP_NAME_1">%2$s</xliff:g> aplikazioak kudeatzen du."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lortu informazio gehiago"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Laneko profila aktibatu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikazioa Android-en bertsio zaharrago baterako sortu zenez, baliteke behar bezala ez funtzionatzea. Bilatu eguneratzerik baden, edo jarri garatzailearekin harremanetan."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Bilatu eguneratzeak"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Mezu berriak dituzu"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baliteke bateria ohi baino lehenago agortzea"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Bateria-aurrezlea"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Desaktibatu egin da bateria-aurrezlea"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Behar adina bateria dauka telefonoak. Jada ez dago eginbiderik murriztuta."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Behar adina bateria dauka tabletak. Jada ez dago eginbiderik murriztuta."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Behar adina bateria dauka gailuak. Jada ez dago eginbiderik murriztuta."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Karpeta"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-erako aplikazioa"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fitxategia"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> kalkulu-orria"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Aurkezpena"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> aurkezpena"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth konexioak aktibatuta jarraituko du hegaldi moduan"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Kargatzen"</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> fitxategi</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktibatu/Desaktibatu pantaila zatitua"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantaila blokeatua"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pantaila-argazkia"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 7d122216b10a..9c3403b57eac 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string> <string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"من"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"گزینههای رایانهٔ لوحی"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"گزینههای Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"دسترسی به تقویم شما"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"پیامک"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"ارسال و مشاهده پیامکها"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"فایلها و رسانهها"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"دسترسی به عکسها، رسانهها و فایلهای روی دستگاهتان"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"میکروفن"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ضبط صدا"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"میتوانید ضربه بزنید، انگشتتان را تند بکشید، انگشتانتان را به هم نزدیک یا از هم دور کنید و اشارههای دیگری اجرا کنید."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"اشارههای اثر انگشت"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"میتواند اشارههای اجراشده روی حسگر اثرانگشت دستگاه را ثبت کند."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"گرفتن نماگرفت"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"میتواند از نمایشگر نماگرفت بگیرد."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"غیرفعال کردن یا تغییر نوار وضعیت"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"به برنامه اجازه میدهد تا نوار وضعیت را غیرفعال کند یا نمادهای سیستم را اضافه یا حذف کند."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"نوار وضعیت باشد"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش میدهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی میتواند به شنواییتان آسیب وارد کند."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"از میانبر دسترسپذیری استفاده شود؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"وقتی میانبر روشن است، اگر هر دو دکمه صدا را ۳ ثانیه فشار دهید یکی از قابلیتهای دسترسپذیری شروع میشود.\n\n قابلیت دسترسپذیری کنونی:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n میتوانید در «تنظیمات > دسترسپذیری»، قابلیت را تغییر دهید."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"خالی"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ویرایش میانبرها"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"لغو"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"خاموش کردن میانبر"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"برنامه در دسترس نیست"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> درحالحاضر در دسترس نیست. <xliff:g id="APP_NAME_1">%2$s</xliff:g> آن را مدیریت میکند."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"بیشتر بدانید"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"نمایه کاری روشن شود؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"برنامهها، اعلانها، دادهها و سایر قابلیتهای نمایه کاری شما روشن خواهد شد"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"این برنامه برای نسخه قدیمیتری از Android ساخته شده است و ممکن است درست کار نکند. وجود بهروزرسانی را بررسی کنید یا با برنامهنویس تماس بگیرید."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"بررسی وجود بهروزرسانی"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"پیامهای جدیدی دارید"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"دستگاه بهاندازه کافی شارژ دارد. ویژگیها دیگر محدود نمیشوند."</string> <string name="mime_type_folder" msgid="2203536499348787650">"پوشه"</string> <string name="mime_type_apk" msgid="3168784749499623902">"برنامه Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"فایل"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> صفحهگسترده"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ارائه"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ارائه"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"بلوتوث درطول حالت هواپیما روشن خواهد بود"</string> <string name="car_loading_profile" msgid="8219978381196748070">"درحال بارگیری"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> فایل</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تغییر وضعیت صفحهٔ دونیمه"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"عکس صفحهنمایش"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index ba39b8c2ca64..a42b87d5d7f2 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Minä"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-laitteen asetukset"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ‑vaihtoehdot"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"käyttää kalenteria"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Tekstiviestit"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"lähettää ja tarkastella tekstiviestejä"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Tiedostot ja media"</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> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Lupa napauttaa, pyyhkäistä, nipistää ja käyttää muita eleitä."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Sormenjälkieleet"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Voi tallentaa laitteen sormenjälkitunnistimelle tehtyjä eleitä."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ota kuvakaappaus"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Voi ottaa kuvakaappauksen näytöstä."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"poista tilapalkki käytöstä tai muokkaa tilapalkkia"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Antaa sovelluksen poistaa tilapalkin käytöstä ja lisätä tai poistaa järjestelmäkuvakkeita."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"sijaita tilapalkissa"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan.\n\n Tällä hetkellä valittu esteettömyystoiminto:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Voit vaihtaa toimintoa valitsemalla Asetukset > Esteettömyys."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Tyhjennä"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muokkaa pikakuvakkeita"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Peruuta"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Poista pikanäppäin käytöstä"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Sovellus ei käytettävissä"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ei ole juuri nyt saatavilla. Tästä vastaa <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Lue lisää"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Otetaanko työprofiili käyttöön?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Työsovellukset, ‑ilmoitukset, ‑tiedot ja muut työprofiiliominaisuudet otetaan käyttöön"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Tämä sovellus on suunniteltu vanhemmalle Android-versiolle eikä välttämättä toimi oikein. Kokeile tarkistaa päivitykset tai ottaa yhteyttä kehittäjään."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tarkista päivitykset"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Sinulle on uusia viestejä"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akku saattaa loppua ennen normaalia latausaikaa"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Virransäästö otettu käyttöön akunkeston pidentämiseksi"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Virransäästö"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Virransäästö laitettiin pois päältä"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Puhelimessa on tarpeeksi virtaa. Ominaisuuksia ei enää rajoiteta."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tabletissa on tarpeeksi virtaa. Ominaisuuksia ei enää rajoiteta."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Laitteessa on tarpeeksi virtaa. Ominaisuuksia ei enää rajoiteta."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Kansio"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-sovellus"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Tiedosto"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-laskentataulukko"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Esitys"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-esitys"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth pysyy päällä myös lentokonetilassa"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Ladataan"</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> tiedostoa</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Jaettu näyttö päälle/pois"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 8df6ad6ed41b..47f41841f747 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Moi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Options d\'Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"accéder à votre agenda"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Messagerie texte"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"envoyer et afficher des messages texte"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Fichiers et contenu multimédia"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"accéder aux photos, aux contenus multimédias et aux fichiers sur votre appareil"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Microphone"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"enregistrer des fichiers audio"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Peut toucher, balayer, pincer et effectuer d\'autres gestes."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestes sur le capteur d\'empreintes digitales"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Peut capturer des gestes effectués sur le capteur d\'empreintes digitales de l\'appareil."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Prendre une capture d\'écran"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Peut prendre une capture de l\'écran."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"désactiver ou modifier la barre d\'état"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"servir de barre d\'état"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité sous Paramètres > Accessibilité."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Vide"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"L\'application n\'est pas accessible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas accessible pour le moment. Ceci est géré par <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Activer le profil professionnel?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, vos notifications, vos données et les autres fonctionnalités de profil professionnel seront activées"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et pourrait ne pas fonctionner correctement. Essayez de vérifier les mises à jour ou communiquez avec son concepteur."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La pile pourrait s\'épuiser avant la charge habituelle"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Le mode Économiseur de pile est activé afin de prolonger l\'autonomie"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Économiseur de pile"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Le mode Économiseur de pile est désactivé"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Le téléphone est suffisamment chargé. Ces fonctionnalités ne sont plus restreintes."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"La tablette est suffisamment chargée. Ces fonctionnalités ne sont plus restreintes."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"L\'appareil est suffisamment chargé. Ces fonctionnalités ne sont plus restreintes."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Dossier"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Application Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fichier"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Feuille de calcul <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Présentation"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Chargement en cours…"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fichier</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Basculer l\'écran partagé"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index a64066a07818..7898e797c8e3 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Moi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Options Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité dans Paramètres > Accessibilité."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Vider"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Application indisponible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas disponible pour le moment. Cette suspension est gérée par l\'application <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Activer profil professionnel ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, notifications, données et d\'autres fonctionnalités de votre profil professionnel seront activées"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et risque de ne pas fonctionner correctement. Recherchez des mises à jour ou contactez le développeur."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Rechercher une mise à jour"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Feuille de calcul <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Présentation"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Présentation <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Le Bluetooth restera activé en mode Avion"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Chargement…"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fichier</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activer/Désactiver l\'écran partagé"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index df08abc861ec..e7498b954194 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcións de Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade.\n\n Función de accesibilidade actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Podes cambiar a función en Configuración > Accesibilidade."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Baleirar"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atallos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar atallo"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"A aplicación non está dispoñible"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicación <xliff:g id="APP_NAME_0">%1$s</xliff:g> non está dispoñible neste momento. A dispoñibilidade está xestionada por <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Máis información"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Activar o perfil de traballo?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Activaranse as túas aplicacións de traballo, as notificacións, os datos e outras funcións do perfil de traballo"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string> - <string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicación deseñouse para unha versión anterior de Android e quizais non funcione correctamente. Proba a buscar actualizacións ou contacta co programador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Buscar actualización"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tes mensaxes novas"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Folla de cálculo <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentación"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentación <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá activado mentres se utilice o modo avión"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</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> ficheiros</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar/desactivar pantalla dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index f663b87492e4..b52d99ef7b8a 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string> <string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"હું"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ટેબ્લેટ વિકલ્પો"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVના વિકલ્પો"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS સંદેશા મોકલવાની અને જોવાની"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ફાઇલો અને મીડિયા"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"તમારા ઉપકરણ પર ફોટો, મીડિયા અને ફાઇલો ઍક્સેસ કરવાની"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"માઇક્રોફોન"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ઑડિઓ રેકોર્ડ કરવાની"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ટૅપ, સ્વાઇપ, પિંચ કરી અને અન્ય હાવભાવ કરી શકે છે."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ફિંગરપ્રિન્ટ સંકેતો"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ડિવાઇસના ફિંગરપ્રિન્ટ સેન્સર પર કરવામાં આવેલા સંકેતો કૅપ્ચર કરી શકે છે."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"સ્ક્રીનશૉટ લો"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ડિસ્પ્લેનો સ્ક્રીનશૉટ લઈ શકે છે."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"સ્ટેટસ બારને અક્ષમ કરો અથવા તેમાં ફેરફાર કરો"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ઍપ્લિકેશનને સ્ટેટસ બાર અક્ષમ કરવાની અથવા સિસ્ટમ આયકન્સ ઉમેરવા અને દૂર કરવાની મંજૂરી આપે છે."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"સ્ટેટસ બારમાં બતાવો"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરીએ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે.\n\n વર્તમાન ઍક્સેસિબિલિટી સુવિધા:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n તમે સેટિંગ્સ > ઍક્સેસિબિલિટીમાં જઈને આ સુવિધા બદલી શકો છો."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ખાલી કરો"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"શૉર્ટકટમાં ફેરફાર કરો"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"રદ કરો"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"શૉર્ટકટ બંધ કરો"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ઍપ ઉપલબ્ધ નથી"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"કાર્યાલયની પ્રોફાઇલ ચાલુ કરીએ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"તમારી કાર્યાલયની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય કાર્યાલયની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"આ ઍપ Androidના જૂના વર્ઝન માટે બનાવવામાં આવ્યું હતું અને તે કદાચ તે યોગ્ય રીતે કાર્ય કરી શકશે નહીં. અપડેટ માટે તપાસવાનો પ્રયાસ કરો અથવા ડેવલપરનો સંપર્ક કરો."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"અપડેટ માટે તપાસો"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"તમારી પાસે નવા સંદેશા છે"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ડિવાઇસમાં પૂરતો ચાર્જ છે. સુવિધાઓ હવે મર્યાદિત નથી."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ફોલ્ડર"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ઍપ"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ફાઇલ"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> સ્પ્રેડશીટ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"પ્રસ્તુતિ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> પ્રસ્તુતિ"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"લોડિંગ"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ફાઇલ</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"સ્ક્રીનને વિભાજિત કરવાની ક્રિયા ટૉગલ કરો"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 81054419ca7b..3140c76ac43c 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string> <string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"मैं"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"टैबलेट विकल्प"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV डिवाइस में फ़ोन से जुड़े विकल्प"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"अपने कैलेंडर को ऐक्सेस करने"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"मैसेज (एसएमएस)"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"मैसेज (एसएमएस) भेजें और देखें"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"फ़ाइलें और मीडिया"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"अपने डिवाइस पर मौजूद फ़ोटो, मीडिया और फ़ाइलें ऐक्सेस करने की"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"माइक्रोफ़ोन"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ऑडियो रिकॉर्ड करें"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"इस सेवा के ज़रिए टैप, स्वाइप, पिंच और बाकी जेस्चर किए जा सकते हैं."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"फ़िंगरप्रिंट जेस्चर"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"डिवाइस के फ़िंगरप्रिंट सेंसर पर किए गए हाथ के जेस्चर (स्पर्श) कैप्चर किए जा सकते हैं."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"स्क्रीनशॉट लें"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"डिसप्ले का स्क्रीनशॉट लिया जा सकता है."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"स्टेटस बार को अक्षम करें या बदलें"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ऐप को, स्टेटस बार को बंद करने या सिस्टम आइकॉन को जोड़ने और निकालने की अनुमति देता है."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"स्टेटस बार को रहने दें"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर ज़्यादा समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"सुलभता शॉर्टकट का इस्तेमाल करना चाहते हैं?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"इस शॉर्टकट के चालू होने पर, दोनों वॉल्यूम बटनों को 3 सेकंड तक दबाने से सुलभता सुविधा शुरू हो जाएगी.\n\n मौजूदा सुलभता सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n आप इस सुविधा को सेटिंग > सुलभता पर जाकर बदल सकते हैं."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"खाली करें"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट में बदलाव करें"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"अभी नहीं"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करें"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"यह ऐप्लिकेशन उपलब्ध नहीं है"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"फ़िलहाल <xliff:g id="APP_NAME_0">%1$s</xliff:g> उपलब्ध नहीं है. इसे <xliff:g id="APP_NAME_1">%2$s</xliff:g> के ज़रिए प्रबंधित किया जाता है."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ज़्यादा जानें"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"वर्क प्रोफ़ाइल चालू करें?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"आपके काम से जुड़े ऐप्लिकेशन, सूचनाएं, डेटा और वर्क प्रोफ़ाइल से जुड़ी दूसरी सुविधाएं चालू हो जाएंगी"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करें"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यह ऐप्लिकेशन Android के पुराने वर्शन के लिए बनाया गया था, इसलिए हो सकता है कि यह सही से काम न करे. देखें कि अपडेट मौजूद हैं या नहीं, या फिर डेवलपर से संपर्क करें."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"देखें कि अपडेट मौजूद है या नहीं"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"आपके पास नए संदेश हैं"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"डिवाइस में काफ़ी बैटरी बची है. सुविधाओं पर अब पाबंदी नहीं है."</string> <string name="mime_type_folder" msgid="2203536499348787650">"फ़ोल्डर"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ऐप्लिकेशन"</string> <string name="mime_type_generic" msgid="4606589110116560228">"फ़ाइल"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> स्प्रेडशीट"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"प्रज़ेंटेशन"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> प्रज़ेंटेशन"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"हवाई जहाज़ मोड के दौरान ब्लूटूथ चालू रहेगा"</string> <string name="car_loading_profile" msgid="8219978381196748070">"प्राेफ़ाइल लोड हो रही है"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> फ़ाइलें</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"स्प्लिट स्क्रीन पर टॉगल करें"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 973718747c62..feb29e22b7ab 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tabletnog uređaja"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string> @@ -1634,7 +1638,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je taj prečac uključen, pritiskom na obje tipke za glasnoću na 3 sekunde pokrenut će se značajka pristupačnosti.\n\n Trenutačna značajka pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Značajku možete promijeniti u Postavkama > Pristupačnost."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prazno"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečace"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečac"</string> @@ -1879,11 +1882,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutačno nije dostupna. Ovime upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Želite uključiti radni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se vaše radne aplikacije, obavijesti, podaci i druge značajke radnog profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ova je aplikacija razvijena za stariju verziju Androida i možda neće funkcionirati pravilno. Potražite ažuriranja ili se obratite razvojnom programeru."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Provjeri ažuriranja"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nove poruke"</string> @@ -2017,6 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> proračunska tablica"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacija"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentacija"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen tijekom načina rada u zrakoplovu"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Učitavanje"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> i još <xliff:g id="COUNT_3">%d</xliff:g> datoteka</item> @@ -2035,5 +2039,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite ili isključite podijeljeni zaslon"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 4884cf7bc2a0..20d38ae44291 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string> <string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Saját"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Táblagép beállításai"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV beállításai"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ha be van kapcsolva a billentyűparancs, a két hangerőgomb 3 másodpercig tartó lenyomásával elindíthatja a kisegítő lehetőségek egyik funkcióját.\n\n A kisegítő lehetőségek jelenleg beállított funkciója:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n A funkciót a Beállítások > Kisegítő lehetőségek menüpontban módosíthatja."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Üres"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Gyorsparancsszerkesztés"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Mégse"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Billentyűparancs kikapcsolása"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Az alkalmazás nem áll rendelkezésre"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> alkalmazás jelenleg nem áll rendelkezésre. Ezt a(z) <xliff:g id="APP_NAME_1">%2$s</xliff:g> kezeli."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"További információ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Bekapcsolja a munkaprofilt?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"A munkahelyi alkalmazások, értesítések, adatok és a munkaprofilhoz tartozó egyéb funkciók be lesznek kapcsolva"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string> - <string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ez az alkalmazás az Android egyik korábbi verziójához készült, így elképzelhető, hogy nem működik majd megfelelően ezen a rendszeren. Keressen frissítéseket, vagy vegye fel a kapcsolatot a fejlesztővel."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Frissítés keresése"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Új üzenetei érkeztek"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-táblázat"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentáció"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-prezentáció"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"A Bluetooth repülős üzemmódban is bekapcsolva marad"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Betöltés"</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> fájl</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Osztott képernyő be- vagy kikapcsolása"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 74915393770f..d13b9ea0770a 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Իմ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Պլանշետի ընտրանքները"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-ի կարգավորումներ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"օգտագործել օրացույցը"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"ուղարկել և դիտել SMS-ները"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Ֆայլեր և մեդիա"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Խոսափող"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ձայնագրել"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Կարող է հպել, թերթել, պտղունցել և կատարել այլ ժեստեր:"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Մատնահետքերի սկաների ժեստեր"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Կարող է արձանագրել մատնահետքերի սկաների վրա կատարվող ժեստերը"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Սքրինշոթի ստեղծում"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Կարող է ստեղծել էկրանի սքրինշոթ։"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"անջատել կամ փոփոխել կարգավիճակի գոտին"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Թույլ է տալիս հավելվածին անջատել կարգավիճակի գոտին կամ ավելացնել ու հեռացնել համակարգի պատկերակները:"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"լինել կարգավիճակի գոտի"</string> @@ -641,7 +642,7 @@ <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Ծրագրին թույլ է տալիս ստանալ Android Beam-ով ընթացիկ փոխանցումների մասին տեղեկատվություն:"</string> <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"հեռացնել DRM վկայագրեր"</string> <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Ծրագրին թույլ է տալիս հեռացնել DRM վկայագրեր: Սովորական ծրագրերի համար երբեք պետք չի գալիս:"</string> - <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"Կապակցում օպերատորի հաղորդագրությունների ծառայության հետ"</string> + <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"Միացում օպերատորի հաղորդագրությունների ծառայության հետ"</string> <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Թույլ է տալիս տիրոջը կապվել օպերատորի հաղորդագրությունների ծառայության վերին մակարդակի միջերեսի հետ: Սա երբեք չի պահանջվում սովորական հավելվածների համար:"</string> <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"կապվել օպերատորի ծառայություններին"</string> <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Թույլ է տալիս սեփականատիրոջը կապվել օպերատորի ծառայություններին: Սովորական հավելվածների դեպքում չի պահանջվում:"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է։\n\n Մատչելիության ակտիվ գործառույթը՝\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Գործառույթը կարող եք փոփոխել՝ անցնելով Կարգավորումներ > Հատուկ գործառույթներ։"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Դատարկ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Փոփոխել դյուրանցումները"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Չեղարկել"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Անջատել դյուրանցումը"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Հավելվածը հասանելի չէ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածը հասանելի չէ։ Դրա աշխատանքը սահմանափակում է <xliff:g id="APP_NAME_1">%2$s</xliff:g> հավելվածը։"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Մանրամասն"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Միացնե՞լ աշխատանքային պրոֆիլը"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Ստուգել նոր տարբերակի առկայությունը"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Դուք ունեք նոր հաղորդագրություններ"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Սարքի լիցքը բավարար է։ Գործառույթներն այլևս չեն սահմանափակվում։"</string> <string name="mime_type_folder" msgid="2203536499348787650">"Պանակ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android հավելված"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Ֆայլ"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> աղյուսակ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Ներկայացում"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ներկայացում"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Ավիառեժիմի ժամանակ Bluetooth-ը չի անջատվի"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Բեռնում"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ֆայլ</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Միացնել/անջատել էկրանի տրոհումը"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 9cfe6d9254e7..c2a081757300 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Saya"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsi tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsi Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas.\n\n Fitur aksesibilitas saat ini:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda dapat mengubah fitur di Setelan > Aksesibilitas."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Kosong"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Nonaktifkan Pintasan"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikasi tidak tersedia"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saat ini tidak tersedia. Aplikasi ini dikelola oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Pelajari lebih lanjut"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Aktifkan profil kerja?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikasi kerja, notifikasi, data, dan fitur profil kerja lainnya akan diaktifkan"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aplikasi ini dibuat untuk Android versi lama dan mungkin tidak berfungsi sebagaimana mestinya. Coba periksa apakah ada update, atau hubungi developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Periksa apakah ada update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Ada pesan baru"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Spreadsheet <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentasi"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentasi <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth akan tetap aktif selama mode pesawat"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Memuat"</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> file</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktifkan/Nonaktifkan Layar Terpisah"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index f7c3b5cec73d..c596c12205e0 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ég"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valkostir spjaldtölvu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Valkostir Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur.\n\n Virkur aðgengiseiginleiki:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Hægt er að skipta um eiginleika í Stillingar > Aðgengi."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Autt"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Breyta flýtileiðum"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hætta við"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slökkva á flýtileið"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Forritið er ekki í boði"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ekki í boði eins og er. Þessu er stjórnað með <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Nánari upplýsingar"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Kveikja á vinnusniði?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Kveikt verður á vinnuforritum, tilkynningum, gögnum og öðrum eiginleikum vinnusniðsins"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Þetta forrit var hannað fyrir eldri útgáfu af Android og ekki er víst að það virki eðlilega. Athugaðu hvort uppfærslur séu í boði eða hafðu samband við þróunaraðilann."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Leita að uppfærslu"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Þú ert með ný skilaboð"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-töflureiknir"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Kynning"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-kynning"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Áfram verður kveikt á Bluetooth í flugstillingu"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Hleður"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> skrá</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Breyta skjáskiptingu"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 387d52e0536d..1144995c069e 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Io"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opzioni tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opzioni Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità.\n\n Funzione di accessibilità corrente:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puoi cambiare la funzione in Impostazioni > Accessibilità."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Svuota"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifica scorciatoie"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annulla"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Disattiva scorciatoia"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App non disponibile"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> non è al momento disponibile. Viene gestita tramite <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ulteriori informazioni"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Attivare il profilo di lavoro?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Le tue app di lavoro, le notifiche, i dati e altri elementi del profilo di lavoro saranno attivati."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string> - <string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Questa app è stata realizzata per una versione precedente di Android e potrebbe non funzionare correttamente. Prova a verificare la disponibilità di aggiornamenti o contatta lo sviluppatore."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verifica la presenza di aggiornamenti"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Hai nuovi messaggi"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Foglio di lavoro <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentazione"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Presentazione <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Il Bluetooth rimane attivo durante l\'uso della modalità aereo"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Caricamento"</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> file</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Attiva/disattiva schermo diviso"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index cf6fa224e4ea..bce62ab631da 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string> <string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"אני"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"אפשרויות טאבלט"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"אפשרויות Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"גישה אל היומן"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"שליחה והצגה של הודעות SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"קבצים ומדיה"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"גישה לתמונות, למדיה ולקבצים במכשיר שלך"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"מיקרופון"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"הקלטת אודיו"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"יכול להקיש, להחליק, לעשות תנועת צביטה ולבצע תנועות אחרות."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"תנועות של טביעות אצבעות"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"אפשרות לזהות תנועות בזמן נגיעה בחיישן טביעות האצבע של המכשיר."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"שמירת צילום המסך"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ניתן לצלם צילום מסך של התצוגה."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"השבת או שנה את שורת המצב"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"מאפשר לאפליקציה להשבית את שורת המצב או להוסיף ולהסיר סמלי מערכת."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"להיות שורת הסטטוס"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת השמע למשך שלוש שניות מפעילה את תכונת הנגישות.\n\n תכונת הנגישות המוגדרת כרגע:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n אפשר לשנות את התכונה בקטע \'הגדרות ונגישות\'."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ריק"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"עריכת קיצורי הדרך"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ביטול"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"כבה את קיצור הדרך"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"האפליקציה אינה זמינה"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"האפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> לא זמינה כרגע. את הזמינות שלה אפשר לנהל באפליקציה <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"מידע נוסף"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"להפעיל את פרופיל העבודה?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"אפליקציות העבודה, התראות, נתונים ותכונות נוספות של פרופיל העבודה יופעלו"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"הפעל"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"האם יש עדכון חדש?"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"יש לך הודעות חדשות"</string> @@ -2033,14 +2031,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"המכשיר טעון מספיק. התכונות כבר לא מוגבלות."</string> <string name="mime_type_folder" msgid="2203536499348787650">"תיקייה"</string> <string name="mime_type_apk" msgid="3168784749499623902">"אפליקציית Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"קובץ"</string> @@ -2059,6 +2053,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"גיליון אלקטרוני <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"מצגת"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"מצגת <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"בטעינה"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="two"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> קבצים</item> @@ -2078,5 +2074,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"החלפת מצב של מסך מפוצל"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index e7f5e854db4b..1ef4a1391860 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string> <string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"自分"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"タブレットオプション"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV のオプション"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"カレンダーへのアクセス"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMSメッセージの送信と表示"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ファイルとメディア"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"デバイス内の写真、メディア、ファイルへのアクセス"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"マイク"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"音声の録音"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"タップ、スワイプ、ピンチ、その他の操作を行えます。"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"指紋認証センサーでの操作"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"デバイスの指紋認証センサーで行われた操作をキャプチャできます。"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"スクリーンショットの撮影"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ディスプレイのスクリーンショットを撮影できます。"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ステータスバーの無効化や変更"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ステータスバーの無効化、システムアイコンの追加や削除をアプリに許可します。"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ステータスバーへの表示"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ショートカットが ON の場合、両方の音量ボタンを 3 秒間押し続けるとユーザー補助機能が起動します。\n\n現在のユーザー補助機能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nユーザー補助機能は [設定] > [ユーザー補助] で変更できます。"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"空"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ショートカットの編集"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"キャンセル"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ショートカットを OFF にする"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"このアプリは使用できません"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"現在、<xliff:g id="APP_NAME_0">%1$s</xliff:g> は使用できません。このアプリの使用は [<xliff:g id="APP_NAME_1">%2$s</xliff:g>] で管理されています。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"詳細"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"仕事用プロファイルの有効化"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"仕事用のアプリ、通知、データなど、仕事用プロファイルの機能が ON になります"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"このアプリは以前のバージョンの Android 用に作成されており、正常に動作しない可能性があります。アップデートを確認するか、デベロッパーにお問い合わせください。"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"アップデートを確認"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"新着メッセージがあります"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"バッテリー セーバーが OFF になりました"</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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"デバイスが十分に充電されました。機能は制限されなくなりました。"</string> <string name="mime_type_folder" msgid="2203536499348787650">"フォルダ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android アプリ"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ファイル"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> スプレッドシート"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"プレゼンテーション"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> プレゼンテーション"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"機内モードでも Bluetooth はオンのままになります"</string> <string name="car_loading_profile" msgid="8219978381196748070">"読み込んでいます"</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> ファイル</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"分割画面の切り替え"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 5d4a56083e23..41b23887e827 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"მე"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ტაბლეტის პარამეტრები"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ვარიანტები"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"თქვენს კალენდარზე წვდომა"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS შეტყობინებების გაგზავნა და ნახვა"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ფაილები და მედია"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"თქვენს მოწყობილობაზე არსებულ ფოტოებზე, მედიასა და ფაილებზე წვდომა"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"მიკროფონი"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"აუდიოს ჩაწერა"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"შეუძლია შეხება, გადაფურცვლა, მასშტაბირება და სხვა ჟესტების შესრულება."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"თითის ანაბეჭდის ჟესტები"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"შეუძლია აღბეჭდოს მოწყობილობის თითის ანაბეჭდის სენსორზე განხორციელებული ჟესტები."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ეკრანის ანაბეჭდის გადაღება"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"შეუძლია ეკრანის ანაბეჭდის გადაღება."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"სტატუსის ზოლის გათიშვა ან ცვლილება"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"აპს შეეძლება სტატუსების ზოლის გათიშვა და სისტემის ხატულების დამატება/წაშლა."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"სტატუსის ზოლის ჩანაცვლება"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"გსურთ მარტივი წვდომის მალსახმობის გამოყენება?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"მალსახმობის ჩართვის შემთხვევაში, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება.\n\n მარტივი წვდომის ამჟამინდელი ფუნქციაა:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ამ ფუნქციის შეცვლა შეგიძლიათ აქ: პარამეტრები > მარტივი წვდომა."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ცარიელი"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"მალსახმობების რედაქტირება"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"გაუქმება"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"მალსახმობის გამორთვა"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"აპი მიუწვდომელია"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ამჟამად მიუწვდომელია. ის იმართება <xliff:g id="APP_NAME_1">%2$s</xliff:g>-ის მიერ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"შეიტყვეთ მეტი"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ჩაირთოს სამსახურის პროფილი?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"თქვენი სამსახურის აპები, შეტყობინებები, მონაცემები და სამსახურის პროფილის ყველა სხვა ფუნქცია ჩაირთვება"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ჩართვა"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ეს აპი Android-ის ძველი ვერსიისთვის შეიქმნა და შესაძლოა სათანადოდ არ მუშაობდეს. გადაამოწმეთ განახლებები ან დაუკავშირდით დეველოპერს."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"განახლების შემოწმება"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"თქვენ ახალი შეტყობინებები გაქვთ"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"მოწყობილობა საკმარისად არის დატენილი. ფუნქციები შეზღუდული აღარ არის."</string> <string name="mime_type_folder" msgid="2203536499348787650">"საქაღალდე"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-ის აპლიკაცია"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ფაილი"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ელცხრილი"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"პრეზენტაცია"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> პრეზენტაცია"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth ჩართული იქნება თვითმფრინავის რეჟიმში"</string> <string name="car_loading_profile" msgid="8219978381196748070">"იტვირთება"</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> ფაილი</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"გაყოფილი ეკრანის გადართვა"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 2acbb17564f1..3ea4d351edd9 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Мен"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет опциялары"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV опциялары"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"күнтізбеге кіру"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS хабарларын жіберу және көру"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлдар және мультимедиа"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"құрылғыдағы фотосуреттерге, мультимедиаға және файлдарға қол жеткізу"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"аудио жазу"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Түртуге, сырғытуға, қысуға және басқа қимылдарды орындауға болады."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Саусақ ізі сканеріндегі қимылдар"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Құрылғының саусақ ізі сенсорында орындалған қимылдарды сақтайды."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Скриншот жасау"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Дисплейдің скриншотын жасай аласыз."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"күйін көрсету тақтасын өшіру немесе өзгерту"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Қолданбаға күй жолағын өшіруге немесе жүйелік белгішелерді қосуға және жоюға рұқсат береді."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"күй жолағы болу"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Бұл төте жол қосулы кезде дыбыс деңгейі түймелерінің екеуін де 3 секунд бойы басқанда арнайы мүмкіндік іске қосылады.\n\n Ағымдағы арнайы мүмкіндік:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Бұл мүмкіндікті \"Параметрлер\" > \"Арнайы мүмкіндіктер\" тармағында өзгертуге болады."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Бос"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Таңбашаларды өзгерту"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Бас тарту"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Қолданба қолжетімді емес"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> дәл қазір қолжетімді емес. Ол <xliff:g id="APP_NAME_1">%2$s</xliff:g> арқылы басқарылады."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Толығырақ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Жұмыс профилі қосылсын ба?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Жұмыс қолданбалары, хабарландырулар, деректер және басқа да жұмыс профильдерінің мүмкіндіктері қосылады"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңартылған нұсқаны тексеру"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея заряды азаюы мүмкін"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарея ұзаққа жетуі үшін, Battery Saver іске қосылды"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Battery Saver"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Battery Saver өшірілді"</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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Құрылғының заряды жеткілікті. Функцияларға енді шектеу қойылмайды."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Қалта"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android қолданбасы"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> электрондық кестесі"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентация"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> презентациясы"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth ұшақ режимінде қосулы болады."</string> <string name="car_loading_profile" msgid="8219978381196748070">"Жүктелуде"</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> файл</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлу мүмкіндігін қосу/өшіру"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 0e277ef59dad..4f7c0febb6ce 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string> <string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ខ្ញុំ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ជម្រើសកុំព្យូទ័របន្ទះ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ជម្រើស Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ចូលប្រើប្រិតិទិនរបស់អ្នក"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"សារ SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"ផ្ញើ និងមើលសារ SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ឯកសារ និងមេឌៀ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ចូលដំណើការរូបភាព មេឌៀ និងឯកសារនៅលើឧបករណ៍របស់អ្នក"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"មីក្រូហ្វូន"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ថតសំឡេង"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"អាចប៉ះ អូស ច្បិច និងធ្វើកាយវិការផ្សេងទៀត"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ចលនាស្នាមម្រាមដៃ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"អាចចាប់យកចលនាដែលធ្វើនៅលើនៅលើឧបករណ៍ចាប់ស្នាមម្រាមដៃរបស់ឧបករណ៍បាន។"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ថតអេក្រង់"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"អាចថតអេក្រង់នៃផ្ទាំងអេក្រង់បាន។"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"បិទ ឬកែរបារស្ថានភាព"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ឲ្យកម្មវិធីបិទរបារស្ថានភាព ឬបន្ថែម និងលុបរូបតំណាងប្រព័ន្ធ។"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ធ្វើជារបារស្ថានភាព"</string> @@ -1617,7 +1618,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"បង្កើនកម្រិតសំឡេងលើសពីកម្រិតបានផ្ដល់យោបល់?\n\nការស្ដាប់នៅកម្រិតសំឡេងខ្លាំងយូរអាចធ្វើឲ្យខូចត្រចៀក។"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ប្រើប្រាស់ផ្លូវកាត់ភាពងាយស្រួល?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"នៅពេលផ្លូវកាត់នេះបើក ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីរឲ្យជាប់រយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយស្រួល។\n\n មុខងារភាពងាយស្រួលបច្ចុប្បន្ន៖\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n អ្នកអាចផ្លាស់ប្តូរមុខងារនេះបាននៅក្នុងការ កំណត់ > ភាពងាយស្រួល។"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"លុបទាំងអស់"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"កែផ្លូវកាត់"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"បោះបង់"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"បិទផ្លូវកាត់"</string> @@ -1852,13 +1852,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"កម្មវិធីមិនអាចប្រើបានទេ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> មិនអាចប្រើបានទេនៅពេលនេះ។ វាស្ថិតក្រោមការគ្រប់គ្រងរបស់ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ។"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ស្វែងយល់បន្ថែម"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"បើកកម្រងព័ត៌មានការងារ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"កម្មវិធីការងារ ការជូនដំណឹង ទិន្នន័យ និងមុខងារកម្រងព័ត៌មានការងារផ្សេងទៀតរបស់អ្នកនឹងត្រូវបានបើក"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"បើក"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"កម្មវិធីនេះត្រូវបានបង្កើតឡើងសម្រាប់កំណែប្រព័ន្ធប្រតិបត្តិការ Android ចាស់ ហើយវាអាចដំណើរការខុសប្រក្រតី។ សូមសាកល្បងពិនិត្យមើលកំណែថ្មី ឬទាក់ទងទៅអ្នកអភិវឌ្ឍន៍។"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"រកមើលកំណែថ្មី"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"អ្នកមានសារថ្មី"</string> @@ -1969,14 +1967,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ឧបករណ៍មានកម្រិតថ្មគ្រប់គ្រាន់។ មុខងារផ្សេងៗមិនត្រូវបានរឹតបន្តឹងទៀតទេ។"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ថត"</string> <string name="mime_type_apk" msgid="3168784749499623902">"កម្មវិធី Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ឯកសារ"</string> @@ -1995,6 +1989,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"បញ្ជី <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"បទបង្ហាញ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"បទបង្ហាញ <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ប៊្លូធូសនឹងនៅបន្តបើក អំឡុងពេលប្រើមុខងារពេលជិះយន្តហោះ"</string> <string name="car_loading_profile" msgid="8219978381196748070">"កំពុងផ្ទុក"</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></item> @@ -2012,5 +2007,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"បិទ/បើកមុខងារបំបែកអេក្រង់"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 50b1bba0131e..9efa85774bab 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ನಾನು"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ಟ್ಯಾಬ್ಲೆಟ್ ಆಯ್ಕೆಗಳು"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ಆಯ್ಕೆಗಳು"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ಫೈಲ್ಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"ಮೈಕ್ರೋಫೋನ್"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ಟ್ಯಾಪ್ ಮಾಡಬಹುದು, ಸ್ವೈಪ್ ಮಾಡಬಹುದು, ಪಿಂಚ್ ಮಾಡಬಹುದು ಮತ್ತು ಇತರ ಗೆಸ್ಚರ್ಗಳನ್ನು ಮಾಡಬಹುದು."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಗೆಶ್ಚರ್ಗಳು"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ಸಾಧನದ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ನಲ್ಲಿ ನಡೆಸಿದ ಗೆಶ್ಚರ್ಗಳನ್ನು ಕ್ಯಾಪ್ಚರ್ ಮಾಡಿ."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಿ"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ಪ್ರದರ್ಶನದ ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಲ್ಲದು."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ ಇಲ್ಲವೇ ಮಾರ್ಪಡಿಸಿ"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಥವಾ ಸೇರಿಸಲು ಮತ್ತು ಸಿಸ್ಟಂ ಐಕಾನ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಾಗಿರಲು"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ವಾಲ್ಯೂಮ್ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಬಳಸುವುದೇ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ ಆನ್ ಮಾಡಲು, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು ನೀವು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಬೇಕು.\n\nಪ್ರಸ್ತುತ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ: \n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಪ್ರವೇಶಿಸುವಿಕೆಯಲ್ಲಿ ನೀವು ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬದಲಾಯಿಸಬಹುದು."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ಖಾಲಿ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ರದ್ದುಗೊಳಿಸಿ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ಶಾರ್ಟ್ಕಟ್ ಆಫ್ ಮಾಡಿ"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ. ಇದನ್ನು <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಆನ್ ಮಾಡುವುದೇ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ನಿಮ್ಮ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳು, ಅಧಿಸೂಚನೆಗಳು, ಡೇಟಾ ಮತ್ತು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆನ್ ಮಾಡಲಾಗುತ್ತದೆ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್ ಮಾಡಿ"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು Android ನ ಹಳೆಯ ಆವೃತ್ತಿಗೆ ರಚಿಸಲಾಗಿದೆ ಮತ್ತು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿರಬಹುದು. ಅಪ್ಡೇಟ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಅಥವಾ ಡೆವಲಪರ್ ಅನ್ನು ಸಂಪರ್ಕಿಸಿ."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ಅಪ್ಡೇಟ್ಗಾಗಿ ಪರಿಶೀಲಿಸಿ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ನೀವು ಹೊಸ ಸಂದೇಶಗಳನ್ನು ಹೊಂದಿರುವಿರಿ"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ಸಾಧನದಲ್ಲಿ ಸಾಕಷ್ಟು ಚಾರ್ಜ್ ಇದೆ. ಇನ್ನು ಮುಂದೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗುವುದಿಲ್ಲ."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ಫೋಲ್ಡರ್"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ಆ್ಯಪ್"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ಫೈಲ್"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ಸ್ಪ್ರೆಡ್ಶೀಟ್"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ಪ್ರಸ್ತುತಿ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ಪ್ರಸ್ತುತಿ"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್ಗಳು</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಟಾಗಲ್ ಮಾಡಿ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 7e12490989cc..90fa0fa65f1d 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string> <string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"나"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"태블릿 옵션"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 옵션"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"캘린더에 액세스"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS 메시지 전송 및 보기"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"파일 및 미디어"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"기기 사진, 미디어, 파일 액세스"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"마이크"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"오디오 녹음"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"탭, 스와이프, 확대/축소 및 기타 동작을 실행할 수 있습니다."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"지문 동작"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"기기 지문 센서에서 동작을 캡처합니다."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"스크린샷 촬영"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"디스플레이 스크린샷을 촬영할 수 있습니다."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"상태 표시줄 사용 중지 또는 수정"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"앱이 상태 표시줄을 사용중지하거나 시스템 아이콘을 추가 및 제거할 수 있도록 허용합니다."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"상태 표시줄에 위치"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"단축키가 사용 설정된 경우 두 개의 볼륨 버튼을 3초간 누르면 접근성 기능이 시작됩니다.\n\n 현재 접근성 기능:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n \'설정 > 접근성\'에서 기능을 변경할 수 있습니다."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"비우기"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"단축키 수정"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"취소"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"단축키 사용 중지"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"앱을 사용할 수 없음"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>은(는) 현재 사용할 수 없습니다. <xliff:g id="APP_NAME_1">%2$s</xliff:g>에서 관리하는 앱입니다."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"자세히 알아보기"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"직장 프로필을 사용 설정하시겠어요?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"업무용 앱, 알림, 데이터 및 기타 직장 프로필 기능이 사용 설정됩니다."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"이 앱은 Android 이전 버전에 맞게 개발되었기 때문에 제대로 작동하지 않을 수 있습니다. 업데이트를 확인하거나 개발자에게 문의하세요."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"업데이트 확인"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"새 메시지 있음"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"기기의 배터리가 충분하므로 기능이 더 이상 제한되지 않습니다"</string> <string name="mime_type_folder" msgid="2203536499348787650">"폴더"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android 애플리케이션"</string> <string name="mime_type_generic" msgid="4606589110116560228">"파일"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> 스프레드시트"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"프레젠테이션"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> 프레젠테이션"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"비행기 모드에서 블루투스가 켜진 상태로 유지됩니다."</string> <string name="car_loading_profile" msgid="8219978381196748070">"로드 중"</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>개</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"화면 분할 모드 전환"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index c887c3451046..07a6e3f75222 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Мен"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет мүмкүнчүлүктөрү"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV параметрлери"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"жылнаамаңызды пайдалануу"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS билдирүүлөрдү жиберүү жана көрсөтүү"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлдар жана медиа"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"түзмөгүңүздөгү сүрөттөрдү жана башка мультимедиа файлдарын пайдаланууга"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"аудио жаздыруу"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Таптап, серпип, чымчып жана башка жаңсоолорду аткара алат."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Манжа изинин жаңсоолору"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Түзмөктөгү манжа изинин сенсорунда жасалган жаңсоолорду жаздырып алат."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Скриншот тартып алуу"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Дисплейдин скриншотун тартып алууга болот."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"абал тилкесин өчүрүү же өзгөртүү"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Колдонмого абал тилкесин өчүрүү же тутум сүрөтчөлөрүн кошуу же алып салуу мүмкүнчүлүгүн берет."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"абал тилкесинин милдетин аткаруу"</string> @@ -843,9 +844,9 @@ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Графикалык ачкычыңызды <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес чийдиңиз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүздүн кулпусун Google аккаунтуңузга кирип ачышыңыз керек болот.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракет кылыңыз."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Сиз планшетиңизди бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар жок кылынат."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Сиз планшетиңизди бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүз демейки жөндөөлөргө кайтарылып, бардык колдонуучу дайындары жоголот."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Сиз телефонуңузду бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар жок кылынат."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Сиз телефонуңузду бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string> <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"Сиз планшетти бөгөттөн чыгарууга <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Планшет баштапкы абалына келтирилет."</string> <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Android TV түзмөгүңүз эми демейки жөндөөлөргө кайтарылат."</string> <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Сиз телефонду бөгөттөн чыгарууга <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Телефон баштапкы абалына келтирилет."</string> @@ -1601,9 +1602,9 @@ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Сиз 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="3328686432962224215">"Сиз сырсөзүңүздү <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_pattern_attempts_dialog_message" msgid="7357404233979139075">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес көрсөттүңүз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин кайталаңыз."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Сиз планшетиңизди <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, планшет баштапкы абалына кайтарылат жана бардык берилиштериңиз жок кылынат."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Сиз планшетиңизди <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, планшет баштапкы абалына кайтарылат жана бардык берилиштериңиз өчүрүлөт."</string> <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүз демейки жөндөөлөргө кайтарылып, бардык колдонуучу дайындары жоголот."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Сиз телефонуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, телефон баштапкы абалына кайтарылат жана бардык берилиштериңиз жок кылынат."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Сиз телефонуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, телефон баштапкы абалына кайтарылат жана бардык берилиштериңиз өчүрүлөт."</string> <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Сиз планшетиңизди <xliff:g id="NUMBER">%d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Планшет баштапкы абалына кайтарылат."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Android TV түзмөгүңүз эми демейки жөндөөлөргө кайтарылат."</string> <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Сиз телефонуңузду <xliff:g id="NUMBER">%d</xliff:g> жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Телефон баштапкы абалына кайтарылат."</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн, ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең үч секунддай кое бербей басып туруңуз.\n\n Учурдагы атайын мүмкүнчүлүктөрдүн жөндөөлөрү:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nЖөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнөн өзгөртө аласыз."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Бошотуу"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Кыска жолдорду түзөтүү"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Жокко чыгаруу"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Кыска жолду өчүрүү"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Колдонмо жеткиликсиз"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> колдонмосу учурда жеткиликсиз. Анын жеткиликтүүлүгү <xliff:g id="APP_NAME_1">%2$s</xliff:g> тарабынан башкарылат."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Кеңири маалымат"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Жумуш профили күйгүзүлсүнбү?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Жумуш колдонмолоруңуз, эскертмелериңиз, дайын-даректериңиз жана жумуш профилинин башка функциялары күйгүзүлөт."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Бул колдонмо Android\'дин эски версиясы үчүн иштеп чыгарылган, андыктан туура эмес иштеши мүмкүн. Жаңыртууларды издеп көрүңүз же иштеп чыгуучуга кайрылыңыз."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңыртууну издөө"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Сизге жаңы билдирүүлөр келди"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Түзмөк жеткиликтүү кубатталды. Функцияны колдоно берсеңиз болот."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Папка"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android колдонмосу"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> форматындагы электр. жадыбал"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентация"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> форматындагы презентация"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth учак режиминде күйүп турат"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Жүктөлүүдө"</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> файл</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлүүнү күйгүзүү же өчүрүү"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 52674c0b09b2..05f9698cd48d 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ຂ້າພະເຈົ້າ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ໂຕເລືອກແທັບເລັດ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ຕົວເລືອກ Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ເຂົ້າຫາປະຕິທິນຂອງທ່ານ"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"ສົ່ງ ແລະເບິ່ງຂໍ້ຄວາມ SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ໄຟລ໌ ແລະ ມີເດຍ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ເຂົ້າເຖິງຮູບຖ່າຍ, ສື່ ແລະໄຟລ໌ຢູ່ເທິງອຸປະກອນຂອງທ່ານ"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"ໄມໂຄຣໂຟນ"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ບັນທຶກສຽງ"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ສາມາດແຕະ, ປັດນີ້ວມື, ຢິບນິ້ວມື ແລະ ດຳເນີນທ່າທາງອື່ນ."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ທ່າທາງລາຍນິ້ວມື"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ສາມາດບັນທຶກທ່າທາງທີ່ເກີດຂຶ້ນໃນອຸປະກອນເຊັນເຊີລາຍນິ້ວມືໄດ້."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ຖ່າຍຮູບໜ້າຈໍ"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ປິດການນນຳໃຊ້ ຫຼື ແກ້ໄຂແຖບສະຖານະ"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ອະນຸຍາດໃຫ້ແອັບຯປິດການເຮັດວຽກຂອງແຖບສະຖານະ ຫຼືເພີ່ມ ແລະລຶບໄອຄອນລະບົບອອກໄດ້."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ເປັນແຖບສະຖານະ"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ເພີ່ມລະດັບສຽງໃຫ້ເກີນກວ່າລະດັບທີ່ແນະນຳບໍ?\n\nການຮັບຟັງສຽງໃນລະດັບທີ່ສູງເປັນໄລຍະເວລາດົນອາດເຮັດໃຫ້ການຟັງຂອງທ່ານມີບັນຫາໄດ້."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ເມື່ອເປີດໃຊ້ປຸ່ມລັດແລ້ວ, ໃຫ້ກົດປຸ່ມສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີເພື່ອເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ.\n\n ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງປັດຈຸບັນ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ທ່ານສາມາດປ່ຽນຄຸນສົມບັດໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ຫວ່າງເປົ່າ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ແກ້ໄຂທາງລັດ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ຍົກເລີກ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ປິດປຸ່ມລັດ"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ບໍ່ສາມາດໃຊ້ແອັບໄດ້"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້. ມັນຖືກຈັດການໂດຍ <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ສຶກສາເພີ່ມເຕີມ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ເປີດໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ແອັບວຽກຂອງທ່ານ, ການແຈ້ງເຕືອນ, ຂໍ້ມູນ ແລະ ຄຸນສົມບັດໂປຣໄຟລ໌ວຽກຈະຖືກເປີດໃຊ້"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ເປີດ"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ແອັບນີ້ຖືກສ້າງຂຶ້ນສຳລັບ Android ເວີຊັນທີ່ເກົ່າກວ່າ ແລະ ອາດເຮັດວຽກໄດ້ບໍ່ປົກກະຕິ. ໃຫ້ລອງກວດສອບເບິ່ງອັບເດດ ຫຼື ຕິດຕໍ່ຜູ້ພັດທະນາ."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ກວດເບິ່ງອັບເດດ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ທ່ານມີຂໍ້ຄວາມໃໝ່"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ອຸປະກອນມີໄຟພຽງພໍແລ້ວ. ບໍ່ມີການຈຳກັດຄຸນສົມບັດອີກຕໍ່ໄປແລ້ວ."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ໂຟນເດີ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"ແອັບພລິເຄຊັນ Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ໄຟລ໌"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"ສະເປຣດຊີດ <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ພຣີເຊັນເທເຊິນ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"ພຣີເຊັນເທເຊິນ <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth ຈະເປີດໄວ້ໃນລະຫວ່າງໂໝດຢູ່ໃນຍົນ"</string> <string name="car_loading_profile" msgid="8219978381196748070">"ກຳລັງໂຫລດ"</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> ໄຟລ໌</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ເປີດ/ປິດການແບ່ງໜ້າຈໍ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 5097d45e9095..4f48685f2a3b 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Aš"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetinio kompiuterio parinktys"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"„Android TV“ parinktys"</string> @@ -1656,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kai spartusis klavišas įjungtas, spaudžiant abu garsumo mygtukus 3 sekundes bus paleista pritaikymo neįgaliesiems funkcija.\n\n Dabartinė pritaikymo neįgaliesiems funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>„\n“\n Funkciją galite pakeisti skiltyje „Nustatymai“ > „Pritaikymas neįgaliesiems“."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Išvalyti"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redaguoti sparčiuosius klavišus"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atšaukti"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Išjungti spartųjį klavišą"</string> @@ -1911,11 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Programa nepasiekiama"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ šiuo metu nepasiekiama. Tai tvarkoma naudojant programą „<xliff:g id="APP_NAME_1">%2$s</xliff:g>“."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Sužinoti daugiau"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Įjungti darbo profilį?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Darbo programos, pranešimai, duomenys ir kitos darbo profilio funkcijos bus išjungtos"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string> - <string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ši programa sukurta naudoti senesnės versijos sistemoje „Android“ ir gali tinkamai neveikti. Pabandykite patikrinti, ar yra naujinių, arba susisiekite su kūrėju."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tikrinti, ar yra naujinių"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Turite naujų pranešimų"</string> @@ -2050,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> skaičiuoklė"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Pristatymas"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> pristatymas"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"„Bluetooth“ liks įjungtas veikiant lėktuvo režimui"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Įkeliama"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one">„<xliff:g id="FILE_NAME_2">%s</xliff:g>“ ir <xliff:g id="COUNT_3">%d</xliff:g> failas</item> @@ -2069,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Perjungti išskaidyto ekrano režimą"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 7d11634f8980..ae9abc6331a3 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Man"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetdatora opcijas"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV opcijas"</string> @@ -290,8 +294,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"piekļūt jūsu kalendāram"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Īsziņas"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"sūtīt un skatīt īsziņas"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Faili un multivides saturs"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"piekļūt fotoattēliem, multividei un failiem jūsu ierīcē"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofons"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ierakstīt audio"</string> @@ -317,10 +320,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Atbalsta pieskaršanos, vilkšanu, savilkšanu un citus žestus."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Pirksta nospieduma žesti"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Var uztvert žestus ierīces pirksta nospieduma sensorā."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ekrānuzņēmuma izveide"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Var izveidot displeja ekrānuzņēmumu."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"atspējot vai pārveidot statusa joslu"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Ļauj lietotnei atspējot statusa joslu vai pievienot un noņemt sistēmas ikonas."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"Būt par statusa joslu"</string> @@ -1637,7 +1638,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ja saīsne ir iespējota, vienlaikus nospiežot abas skaļuma regulēšanas pogas un trīs sekundes turot tās, tiks palaista pieejamības funkcija.\n\n Pašreiz iestatītā pieejamības funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Šo funkciju var mainīt sadaļā Iestatījumi > Pieejamība."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Notīrīt"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediģēt īsinājumtaustiņus"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atcelt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izslēgt saīsni"</string> @@ -1882,13 +1882,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Lietotne nav pieejama"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pašlaik nav pieejama. Šo darbību pārvalda <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Uzzināt vairāk"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Vai ieslēgt darba profilu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Tiks ieslēgtas jūsu darba lietotnes, paziņojumi, dati un citas darba profila funkcijas."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Šī lietotne tika izstrādāta vecākai Android versijai un var nedarboties pareizi. Meklējiet atjauninājumus vai sazinieties ar izstrādātāju."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Meklēt atjauninājumu"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Jums ir jaunas īsziņas."</string> @@ -2000,14 +1998,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora jaudas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora jaudas taupīšanas režīms"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora jaudas taupīšanas režīms ir izslēgts"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Tālruņa uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Planšetdatora uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Ierīces uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Mape"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android lietojumprogramma"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fails"</string> @@ -2026,6 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> izklājlapa"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentācija"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentācija"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth joprojām būs ieslēgts lidojuma režīmā."</string> <string name="car_loading_profile" msgid="8219978381196748070">"Ielāde"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="zero"><xliff:g id="FILE_NAME_2">%s</xliff:g> un <xliff:g id="COUNT_3">%d</xliff:g> failu</item> @@ -2044,5 +2039,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Pārslēgt ekrāna sadalīšanu"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 72048b5dc6bb..f1e54064036f 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Јас"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции на таблет"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции на Android TV"</string> @@ -1614,7 +1618,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да го зголемиме звукот над препорачаното ниво?\n\nСлушањето звуци со голема јачина подолги периоди може да ви го оштети сетилото за слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Да се користи кратенка за „Пристапност“?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција на пристапност.\n\n Тековна функција на пристапност:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Функцијата може да ја промените во „Поставки“ > „Пристапност“."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Испразни"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменете ги кратенките"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Откажи"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Исклучи ја кратенката"</string> @@ -1849,11 +1852,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апликацијата не е достапна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Апликацијата <xliff:g id="APP_NAME_0">%1$s</xliff:g> не е достапна во моментов. Со ова управува <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Дознај повеќе"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Да се вклучи работниот профил?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Вашите работни апликации, известувања, податоци и други функции на работниот профил ќе бидат вклучени"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Вклучи"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Апликацијава е создадена за постара верзија на Android и може да не функционира правилно. Проверете за ажурирања или контактирајте со програмерот."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверка за ажурирање"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нови пораки"</string> @@ -1986,6 +1989,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-табела"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентација"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-презентација"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth ќе остане вклучен при авионски режим"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Се вчитува"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> датотека</item> @@ -2003,5 +2007,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Вклучи/исклучи поделен екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index b0bbb670146d..f0cc48cf9bd9 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string> <string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ഞാന്"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ടാബ്ലെറ്റ് ഓപ്ഷനുകൾ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ടിവി ഓപ്ഷനുകൾ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ്സ് ചെയ്യുക"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS സന്ദേശങ്ങൾ അയയ്ക്കുകയും കാണുകയും ചെയ്യുക"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ഫയലുകളും മീഡിയയും"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"നിങ്ങളുടെ ഉപകരണത്തിലെ ഫോട്ടോകളും മീഡിയയും ഫയലുകളും ആക്സസ് ചെയ്യുക"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"മൈക്രോഫോണ്"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ടാപ്പുചെയ്യാനോ സ്വൈപ്പുചെയ്യാനോ പിഞ്ചുചെയ്യാനോ മറ്റ് ജെസ്റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ഫിംഗർപ്രിന്റ് ജെസ്റ്ററുകൾ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ഉപകരണത്തിന്റെ ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെയ്ത ജെസ്റ്ററുകൾ ക്യാപ്ചർ ചെയ്യാനാകും."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"സ്ക്രീന്ഷോട്ട് എടുക്കുക"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ഡിസ്പ്ലേയുടെ സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിയും."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"സ്റ്റാറ്റസ് ബാർ പ്രവർത്തനരഹിതമാക്കുക അല്ലെങ്കിൽ പരിഷ്ക്കരിക്കുക"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"നില ബാർ പ്രവർത്തരഹിതമാക്കുന്നതിന് അല്ലെങ്കിൽ സിസ്റ്റം ഐക്കണുകൾ ചേർക്കുന്നതിനും നീക്കംചെയ്യുന്നതിനും അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"സ്റ്റാറ്റസ് ബാർ ആയിരിക്കുക"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കണോ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"കുറുക്കുവഴി ഓണാണെങ്കിൽ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും.\n\n നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ക്രമീകരണം > ഉപയോഗസഹായി എന്നതിൽ ഏത് സമയത്തും നിങ്ങൾക്ക് ഫീച്ചർ മാറ്റാവുന്നതാണ്."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ശൂന്യം"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"കുറുക്കുവഴികൾ തിരുത്തുക"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"റദ്ദാക്കുക"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"കുറുക്കുവഴി ഓഫാക്കുക"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ആപ്പ് ലഭ്യമല്ല"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല. <xliff:g id="APP_NAME_1">%2$s</xliff:g> ആണ് ഇത് മാനേജ് ചെയ്യുന്നത്."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"കൂടുതലറിയുക"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കണോ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"നിങ്ങളുടെ ഔദ്യോഗിക ആപ്പുകൾ, അറിയിപ്പുകൾ, ഡാറ്റ, മറ്റ് ഔദ്യോഗിക പ്രൊഫൈൽ ഫീച്ചറുകൾ എന്നിവ ഓണാക്കും"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ഓണാക്കുക"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ഈ ആപ്പ് Android-ന്റെ പഴയ പതിപ്പിനായി നിർമ്മിച്ചിരിക്കുന്നതിനാൽ ശരിയായി പ്രവർത്തിച്ചേക്കില്ല. അപ്ഡേറ്റിനായി പരിശോധിക്കുക, അല്ലെങ്കിൽ ഡെവലപ്പറുമായി ബന്ധപ്പെടുക."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"അപ്ഡേറ്റിനായി പരിശോധിക്കുക"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"നിങ്ങൾക്ക് പുതിയ സന്ദേശങ്ങൾ ഉണ്ട്"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ഉപകരണത്തിൽ വേണ്ടത്ര ചാർജ് ഉണ്ട്. ഫീച്ചറുകൾക്ക് ഇനി നിയന്ത്രണമില്ല."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ഫോള്ഡര്"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ആപ്പ്"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ഫയൽ"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> സ്പ്രെഡ്ഷീറ്റ്"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"അവതരണം"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> അവതരണം"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"ലോഡ് ചെയ്യുന്നു"</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> ഫയലുകൾ</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"സ്ക്രീൻ വിഭജന മോഡ് മാറ്റുക"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്ക്രീൻ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 205df2770748..3be3a0442401 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Би"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Таблетын сонголтууд"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ТВ-н сонголт"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"Хуанли руу хандах"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Мессеж"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS мессежийг илгээх, харах"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файл болон мeдиа"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"Tөхөөрөмж дээрх зураг, медиа болон файлд хандалт хийх"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"дуу хураах"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Товших, шудрах, жижигрүүлэх болон бусад зангааг хийх боломжтой."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Хурууны хээний зангаа"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Төхөөрөмжийн хурууны хээ мэдрэгчид зангасан зангааг танина."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Дэлгэцийн зургийг дарах"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Дэлгэцийн зургийг дарах боломжтой."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"статус самбарыг идэвхгүй болгох болон өөрчлөх"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Апп нь статус самбарыг идэвхгүй болгох эсвэл систем дүрсийг нэмэх, хасах боломжтой."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"статусын хэсэг болох"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Товчлолыг асаасан үед дуун товчлуурыг 3 секунд дарснаар хүртээмжийн онцлогийг эхлүүлнэ.\n\n Одоогийн хүртээмжийн онцлог:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Онцлогийг Тохиргоо > Хүртээмж хэсэгт өөрчлөх боломжтой."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Хоосон"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Товчлолуудыг засах"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Болих"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Товчлолыг унтраах"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апп боломжгүй байна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> одоогоор боломжгүй байна. Үүнийг <xliff:g id="APP_NAME_1">%2$s</xliff:g>-р удирддаг."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Дэлгэрэнгүй үзэх"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ажлын профайлыг асаах уу?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Таны ажлын апп, мэдэгдэл, өгөгдөл болон бусад ажлын профайлын онцлогийг асаана"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Асаах"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Энэ аппыг Андройдын хуучин хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Шинэчлэлтийг шалгаж эсвэл хөгжүүлэгчтэй холбогдоно уу."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шинэчлэлтийг шалгах"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ зурвасууд байна"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Төхөөрөмж хангалттай цэнэгтэй боллоо. Онцлогуудыг цаашид хязгаарлахгүй."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Фолдер"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Андройд апп"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-н хүснэгт"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Үзүүлэн"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-н үзүүлэн"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"Ачаалж байна"</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> файл</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Дэлгэц хуваахыг унтраах/асаах"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index b27e1c9c8f94..a2bf4796eaec 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"मी"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"टॅबलेट पर्याय"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV पर्याय"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"आपल्या कॅलेंडरवर प्रवेश"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS मेसेज पाठवणे आणि पाहणे हे"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"फाइल आणि मीडिया"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"तुमच्या डिव्हाइस वरील फोटो, मीडिया आणि फायलींमध्ये अॅक्सेस"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"मायक्रोफोन"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ऑडिओ रेकॉर्ड"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"टॅप, स्वाइप, पिंच आणि इतर जेश्चर करू शकते."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"फिंगरप्रिंट जेश्चर"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"डिव्हाइसच्या फिंगरप्रिंट सेंन्सरवरील जेश्चर कॅप्चर करू शकते."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"स्क्रीनशॉट घ्या"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"डिस्प्लेचा स्क्रीनशॉट घेऊ शकतो."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"स्टेटस बार अक्षम करा किंवा सुधारित करा"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"स्टेटस बार अक्षम करण्यासाठी किंवा सिस्टम चिन्हे जोडण्यासाठी आणि काढण्यासाठी अॅप ला अनुमती देते."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"स्टेटस बार होऊ द्या"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"शिफारस केलेल्या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्याने आपल्या श्रवणशक्तीची हानी होऊ शकते."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"शॉर्टकट चालू असताना, दोन्ही आवाज बटणे 3 सेकंद दाबल्याने प्रवेशयोग्यता वैशिष्ट्य सुरू होईल.\n\n वर्तमान प्रवेशयोग्यता वैशिष्ट्य:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तुम्ही सेटिंग्ज > प्रवेशयोग्यता मध्ये वैशिष्ट्य बदलू शकता."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"रिकामे करा"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट संपादित करा"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द करा"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करा"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"अॅप उपलब्ध नाही"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल चालू ठेवायची?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये चालू केली जातील"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करा"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"हे अॅप Android च्या जुन्या आवृत्ती साठी तयार करण्यात आले होते आणि योग्यरितीने कार्य करू शकणार नाही. अपडेट आहेत का ते तपासून पाहा, किंवा डेव्हलपरशी संपर्क साधण्याचा प्रयत्न करा."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अपडेट आहे का ते तपासा"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"आपल्याकडे नवीन मेसेज आहेत"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"डिव्हाइस पुरेसे चार्ज केलेले आहे. वैशिष्ट्ये मर्यादित नाहीत."</string> <string name="mime_type_folder" msgid="2203536499348787650">"फोल्डर"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android अॅप्लिकेशन"</string> <string name="mime_type_generic" msgid="4606589110116560228">"फाइल"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> स्प्रेडशीट"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"सादरीकरण"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> सादरीकरण"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"विमान मोड दरम्यान ब्लूटूथ चालू राहील"</string> <string name="car_loading_profile" msgid="8219978381196748070">"लोड होत आहे"</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> फायली</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रीन टॉगल करा"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index a29e363d56c7..f7626dbe1935 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Saya"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Pilihan tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Pilihan Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"mengakses kalendar"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"menghantar dan melihat mesej SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Fail dan media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"mengakses foto, media dan fail pada peranti anda"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"rakam audio"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Boleh ketik, leret, cubit dan laksanakan gerak isyarat lain."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gerak isyarat cap jari"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Boleh menangkap gerak isyarat yang dilakukan pada penderia cap jari peranti."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ambil tangkapan skrin"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Boleh mengambil tangkapan skrin paparan."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"lumpuhkan atau ubah suai bar status"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Membenarkan apl melumpuhkan bar status atau menambah dan mengalih keluar ikon sistem."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"jadi bar status"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan.\n\n Ciri kebolehaksesan semasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda boleh menukar ciri itu dalam Tetapan > Kebolehaksesan."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Kosong"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Matikan pintasan"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Apl tidak tersedia"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tidak tersedia sekarang. Ini diurus oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ketahui lebih lanjut"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Hidupkan profil kerja?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Apl kerja, pemberitahuan, data dan ciri profil kerja anda yang lain akan dihidupkan"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Apl ini dibina untuk versi Android yang lebih lama dan mungkin tidak berfungsi dengan betul. Cuba semak kemas kini atau hubungi pembangun."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Semak kemas kini"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Anda mempunyai mesej baharu"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateri mungkin habis sebelum pengecasan biasa"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penjimat Bateri diaktifkan untuk memanjangkan hayat bateri"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Penjimat Bateri"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Penjimat Bateri dimatikan"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Cas telefon mencukupi. Ciri tidak lagi dihadkan."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Cas tablet mencukupi. Ciri tidak lagi dihadkan."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Cas peranti mencukupi. Ciri tidak lagi dihadkan."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Folder"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplikasi Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fail"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Hamparan <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Pembentangan"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Pembentangan <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth akan kekal hidup semasa dalam mod pesawat"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Memuatkan"</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> fail</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Togol Skrin Pisah"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index a53deafd6fd8..556837efa8a3 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string> <string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ကျွန်ုပ်"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletဆိုင်ရာရွေးချယ်မှုများ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ရွေးချယ်စရာများ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS စာတိုစနစ်"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS စာများကို ပို့ကာ ကြည့်မည်"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Files နှင့် မီဒီယာ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"သင့်ဖုန်းရှိ ဓာတ်ပုံများ၊ မီဒီယာနှင့် ဖိုင်များအား ဝင်သုံးပါ"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"မိုက်ခရိုဖုန်း"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"အသံဖမ်းခြင်း"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"တို့ခြင်း၊ ပွတ်ဆွဲခြင်း၊ နှင့် အခြား လက်ဟန်များကို အသုံးပြုနိုင်ပါသည်။"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"လက်ဗွေဟန်များ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"စက်ပစ္စည်း၏ လက်ဗွေအာရုံခံကိရိယာတွင် လုပ်ဆောင်ထားသည့် လက်ဟန်များကို မှတ်သားထားနိုင်သည်။"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ဖန်သားပြင်ဓာတ်ပုံ ရိုက်ရန်"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ဖန်သားပြင်ပြသမှုကို ဓာတ်ပုံရိုက်နိုင်ပါသည်။"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"အခြေအနေပြဘားအား အလုပ်မလုပ်ခိုင်းရန်သို့မဟုတ် မွမ်းမံရန်"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"အက်ပ်အား အခြေအနေပြ ဘားကို ပိတ်ခွင့် သို့မဟတ် စနစ် အိုင်ကွန်များကို ထည့်ခြင်း ဖယ်ရှားခြင်း ပြုလုပ်ခွင့် ပြုသည်။"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံအတိုးအလျှော့ခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။\n\n လက်ရှိ အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှု−\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ဝန်ဆောင်မှုကို ဆက်တင်များ > အများသုံးစွဲနိုင်မှုတွင် ပြောင်းလဲနိုင်ပါသည်။"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"အလွတ်"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ဖြတ်လမ်းများကို တည်းဖြတ်ရန်"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"မလုပ်တော့"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ဖြတ်လမ်းလင့်ခ်ကို ပိတ်ရန်"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"အက်ပ်ကို မရရှိနိုင်ပါ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ကို လောလောဆယ် မရနိုင်ပါ။ ၎င်းကို <xliff:g id="APP_NAME_1">%2$s</xliff:g> က စီမံထားပါသည်။"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ပိုမိုလေ့လာရန်"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"အလုပ်ပရိုဖိုင် ဖွင့်လိုသလား။"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"သင်၏ အလုပ်အက်ပ်၊ အကြောင်းကြားချက်၊ ဒေတာနှင့် အခြားအလုပ်ပရိုဖိုင် ဝန်ဆောင်မှုများကို ဖွင့်လိုက်ပါမည်"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ဖွင့်ပါ"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ဤအက်ပ်ကို Android ဗားရှင်းဟောင်းအတွက် ပြုလုပ်ထားခြင်းဖြစ်ပြီး ပုံမှန်အလုပ်မလုပ်နိုင်ပါ။ အပ်ဒိတ်များအတွက် ရှာကြည့်ပါ သို့မဟုတ် ဆော့ဖ်ဝဲအင်ဂျင်နီယာကို ဆက်သွယ်ပါ။"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"အပ်ဒိတ်စစ်ရန်"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"သင့်ထံတွင် စာအသစ်များရောက်နေသည်"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"စက်တွင် ဘက်ထရီအား အလုံအလောက် ရှိသည်။ လုပ်ဆောင်ချက်များကို ကန့်သတ်မထားတော့ပါ။"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ဖိုင်တွဲ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android အပလီကေးရှင်း"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ဖိုင်"</string> @@ -1993,6 +1987,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">"တင်ပြမှု"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> တင်ပြမှု"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"လေယာဉ်ပျံမုဒ်ကို ဖွင့်ထားစဉ် ဘလူးတုသ် ပွင့်နေပါမည်"</string> <string name="car_loading_profile" msgid="8219978381196748070">"တင်နေသည်"</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> ဖိုင်</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို နှိပ်ပါ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index ee16f90e6077..6f3b6c213cad 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Meg"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Innstillinger for nettbrettet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-alternativer"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"åpne kalenderen din"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"sende og lese SMS-meldinger"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Filer og medier"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"åpne bilder, medieinnhold og filer på enheten din"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ta opp lyd"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan trykke, sveipe, klype og gjøre andre bevegelser."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Bevegelser på fingeravtrykkssensor"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan fange inn bevegelser som utføres på enhetens fingeravtrykkssensor."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ta skjermdump"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Kan ikke ta en skjermdump av skjermen."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"deaktivere eller endre statusfeltet"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Lar appen deaktivere statusfeltet eller legge til og fjerne systemikoner."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"vise appen i statusfeltet"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder.\n\n Nåværende tilgjengelighetsfunksjon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan endre funksjonen i Innstillinger > Tilgjengelighet."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Tøm"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Endre snarveier"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slå av snarveien"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgjengelig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgjengelig akkurat nå. Dette administreres av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Finn ut mer"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Vil du slå på jobbprofilen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappene dine samt varsler, data og andre funksjoner i jobbprofilen din blir slått på"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Denne appen er utviklet for en eldre versjon av Android og fungerer kanskje ikke som den skal. Prøv å se etter oppdateringer, eller kontakt utvikleren."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Se etter oppdateringer"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nye meldinger"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan gå tomt før den vanlige ladingen"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparing er aktivert for å forlenge batterilevetiden"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Batterisparing"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Batterisparing er slått av"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonen har nok batteri. Funksjoner begrenses ikke lenger."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Nettbrettet har nok batteri. Funksjoner begrenses ikke lenger."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Enheten har nok batteri. Funksjoner begrenses ikke lenger."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Mappe"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android-app"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fil"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-regneark"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Presentasjon"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-presentasjon"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth holdes på i flymodus"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Laster inn"</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> filer</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå delt skjerm av/på"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 1b85b28e6a61..ebbf50bf41e4 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको अनुप्रयोग प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"मलाई"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ट्याब्लेट विकल्पहरू"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV सम्बन्धी विकल्पहरू"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"तपाईंको पात्रोमाथि पहुँच गर्नुहोस्"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"फाइल र मिडिया"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"तपाईंको यन्त्रमा तस्बिर, मिडिया, र फाइलहरूमाथि पहुँच गर्नुहोस्"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"माइक्रोफोन"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"अडियो रेकर्ड गर्नुहोस्"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ट्याप, स्वाइप गर्न, थिच्न र अन्य इसाराहरू सम्बन्धी कार्य गर्न सक्छ"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"फिंगरप्रिन्टका इसाराहरू"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"यसले यन्त्रको फिंगरप्रिन्टसम्बन्धी सेन्सरमा गरिएका इसाराहरूलाई खिच्न सक्छ।"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"स्क्रिनसट लिनुहोस्"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"डिस्प्लेको स्क्रिनसट लिन सकिन्छ।"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"स्थिति पट्टिलाई अक्षम वा संशोधित गर्नुहोस्"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"स्थिति पट्टि असक्षम पार्न वा प्रणाली आइकनहरू थप्न र हटाउन अनुप्रयोगलाई अनुमति दिन्छ।"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"वस्तुस्थिति पट्टी हुन दिनुहोस्"</string> @@ -1621,7 +1622,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"सर्टकट सक्रिय हुँदा, भोल्युमका दुवै बटनहरूलाई ३ सेकेन्डसम्म थिची राख्नाले पहुँच सम्बन्धी कुनै सुविधा सुरु हुनेछ।\n\n हाल व्यवहारमा रहेको पहुँच सम्बन्धी सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तपाईं सेटिङहरू अन्तर्गतको पहुँच सम्बन्धी विकल्पमा गई उक्त सुविधालाई बदल्न सक्नुहुन्छ।"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"खाली"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"सर्टकटहरू सम्पादन गर्नुहोस्"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द गर्नुहोस्"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"सर्टकटलाई निष्क्रिय पार्नुहोस्"</string> @@ -1856,13 +1856,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"अनुप्रयोग उपलब्ध छैन"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> अहिले उपलब्ध छैन। यो <xliff:g id="APP_NAME_1">%2$s</xliff:g> द्वारा व्यवस्थित छ।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"थप जान्नुहोस्"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल सक्रिय गर्ने?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"तपाईंका कार्यसम्बन्धी अनुप्रयोग, सूचना, डेटा र कार्य प्रोफाइलका अन्य सुविधाहरू सक्रिय गरिने छन्"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"सक्रिय गर्नुहोस्"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"यो अनुप्रयोग Android को पुरानो संस्करणका लागि बनाइएको हुनाले यसले सही ढङ्गले काम नगर्न सक्छ। अद्यावधिकहरू उपलब्ध छन् वा छैनन् भनी जाँच गरी हेर्नुहोस् वा यसको विकासकर्तालाई सम्पर्क गर्नुहोस्।"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"अद्यावधिक उपलब्ध छ वा छैन भनी जाँच गर्नुहोस्"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"तपाईंलाई नयाँ सन्देश आएको छ"</string> @@ -1973,14 +1971,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"यन्त्रमा पर्याप्त चार्ज छ। सुविधाहरूलाई अब उप्रान्त प्रतिबन्ध लगाइँदैन।"</string> <string name="mime_type_folder" msgid="2203536499348787650">"फोल्डर"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android अनुप्रयोग"</string> <string name="mime_type_generic" msgid="4606589110116560228">"फाइल"</string> @@ -1999,6 +1993,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> स्प्रेडसिट"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"प्रस्तुति"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> प्रस्तुति"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"लोड गर्दै"</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> फाइलहरू</item> @@ -2016,5 +2012,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रिन टगल गर्नुहोस्"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index dece9ae55b7f..0635c214a4c1 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string> <string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ik"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletopties"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opties voor Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen > Toegankelijkheid."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Leeg"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuleren"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Sneltoets uitschakelen"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"App is niet beschikbaar"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nu niet beschikbaar. Dit wordt beheerd door <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Meer info"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Werkprofiel inschakelen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Je werk-apps, meldingen, gegevens en andere functies van je werkprofiel worden uitgeschakeld"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Inschakelen"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Deze app is ontwikkeld voor een oudere versie van Android en werkt mogelijk niet op de juiste manier. Controleer op updates of neem contact op met de ontwikkelaar."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Controleren op update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Je hebt nieuwe berichten"</string> @@ -1984,6 +1987,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">"Presentatie"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g>-presentatie"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth blijft ingeschakeld in de vliegtuigmodus"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Laden"</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> bestanden</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Gesplitst scherm schakelen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 2018a7fd4a27..03a7ea3be704 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ମୁଁ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ଟାବଲେଟ୍ର ବିକଳ୍ପ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ଟିଭିର ବିକଳ୍ପଗୁଡ଼ିକ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ଆପଣଙ୍କ କ୍ୟାଲେଣ୍ଡର୍ ଆକ୍ସେସ୍ କରେ"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ମେସେଜ୍ ପଠାନ୍ତୁ ଓ ଦେଖନ୍ତୁ"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ଫାଇଲଗୁଡ଼ିକ ଏବଂ ମିଡିଆ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ଥିବା ଫଟୋ, ମିଡିଆ ଓ ଫାଇଲ୍ ଆକ୍ସେସ୍ କରେ"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"ମାଇକ୍ରୋଫୋନ୍"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ଅଡିଓ ରେକର୍ଡ କରେ"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ଟାପ୍, ସ୍ୱାଇପ୍, ପିଞ୍ଚ ଓ ଅନ୍ୟାନ୍ୟ ଜେଶ୍ଚର୍ ସମ୍ପାଦନ କରିପାରିବ।"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ଟିପଚିହ୍ନ ଜେଶ୍ଚର"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ଡିଭାଇସ୍ର ଟିପଚିହ୍ନ ସେନସର୍ ଉପରେ ଜେଶ୍ଚର୍ କ୍ୟାପଚର୍ କାର୍ଯ୍ୟ କରାଯାଇପାରିବ।"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ସ୍କ୍ରିନସଟ୍ ନିଅନ୍ତୁ"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ଡିସପ୍ଲେର ଏକ ସ୍କ୍ରିନସଟ୍ ନିଆଯାଇପାରେ।"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ଷ୍ଟାଟସ୍ ବାର୍କୁ ଅକ୍ଷମ କିମ୍ୱା ସଂଶୋଧନ କରନ୍ତୁ"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ଆପ୍କୁ, ସ୍ଥିତି ବାର୍ ଅକ୍ଷମ କରିବାକୁ କିମ୍ବା ସିଷ୍ଟମ୍ ଆଇକନ୍ ଯୋଡ଼ିବା କିମ୍ବା ବାହାର କରିବାକୁ ଦେଇଥାଏ।"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ଷ୍ଟାଟସ୍ ବାର୍ ରହିବାକୁ ଦିଅନ୍ତୁ"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରିବେ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ସର୍ଟକଟ୍ ଅନ୍ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ ଆରମ୍ଭ ହେବ।\n\n ସମ୍ପ୍ରତି ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ୍ୟ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ସେଟିଙ୍ଗ ଓ ଆକ୍ସେସବିଲିଟିରେ ଆପଣ ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇ ପାରିବେ।"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ଖାଲି କରନ୍ତୁ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ସର୍ଟକଟଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ବାତିଲ୍ କରନ୍ତୁ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ଶର୍ଟକଟ୍ ବନ୍ଦ କରନ୍ତୁ"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ଚାଲୁ କରିବେ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ଆପଣଙ୍କର କାର୍ଯ୍ୟକାରୀ ଆପ୍, ବିଜ୍ଞପ୍ତି, ଡାଟା ଓ ଅନ୍ୟ ୱର୍କ ପ୍ରୋଫାଇଲ୍ଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ଅନ୍ କରନ୍ତୁ"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ଏହି ଆପ୍କୁ Androidର ପୁରୁଣା ଭର୍ସନ୍ ପାଇଁ ନିର୍ମାଣ କରାଯାଇଥିଲା ଏବଂ ଠିକ୍ ଭାବେ କାମ କରିନପାରେ। ଏହାପାଇଁ ଅପଡେଟ୍ ଅଛି କି ନାହିଁ ଯାଞ୍ଚ କରନ୍ତୁ କିମ୍ବା ଡେଭେଲପର୍ଙ୍କ ସହିତ ସମ୍ପର୍କ କରନ୍ତୁ।"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ଅପଡେଟ୍ ପାଇଁ ଯାଞ୍ଚ କରନ୍ତୁ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ଆପଣଙ୍କ ପାଖରେ ନୂଆ ମେସେଜ୍ ରହିଛି"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ଡିଭାଇସରେ ଯଥେଷ୍ଟ ଚାର୍ଜ ଅଛି। ଫିଚରଗୁଡ଼ିକ ଆଉ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ।"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ଫୋଲ୍ଡର୍"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ଆପ୍ଲିକେସନ୍"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ଫାଇଲ୍"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ସ୍ପ୍ରେଡ୍ସିଟ୍"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ଉପସ୍ଥାପନା"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ଉପସ୍ଥାପନା"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"ଲୋଡ୍ ହେଉଛି"</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>ଟି ଫାଇଲ୍</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ଦୁଇଟି ସ୍କ୍ରିନ୍ ମଧ୍ୟରେ ଟୋଗଲ୍ କରନ୍ତୁ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 552f77d9307b..b2cca4db6615 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ਮੈਂ"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ਟੈਬਲੈੱਟ ਵਿਕਲਪ"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ਦੇ ਵਿਕਲਪ"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਦੇਖੋ"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ਫ਼ਾਈਲਾਂ ਅਤੇ ਮੀਡੀਆ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫ਼ਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨਾ"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">" ਆਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"ਟੈਪ ਕਰ ਸਕਦੀ ਹੈ, ਸਵਾਈਪ ਕਰ ਸਕਦੀ ਹੈ, ਚੂੰਢੀ ਭਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਹੋਰ ਸੰਕੇਤ ਕਰ ਸਕਦੀ ਹੈ।"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੰਕੇਤ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"ਡੀਵਾਈਸਾਂ ਦੇ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ \'ਤੇ ਕੀਤੇ ਗਏ ਸੰਕੇਤਾਂ ਨੂੰ ਕੈਪਚਰ ਕਰ ਸਕਦੇ ਹਨ।"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਓ"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ਡਿਸਪਲੇ ਦਾ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈ ਸਕਦੀ ਹੈ।"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ਸਥਿਤੀ ਪੱਟੀ ਬੰਦ ਕਰੋ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ਐਪ ਨੂੰ ਸਥਿਤੀ ਪੱਟੀ ਨੂੰ ਚਾਲੂ ਕਰਨ ਜਾਂ ਸਿਸਟਮ ਪ੍ਰਤੀਕਾਂ ਨੂੰ ਜੋੜਨ ਅਤੇ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"ਸਥਿਤੀ ਪੱਟੀ ਬਣਨ ਦਿਓ"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ਕੀ ਵੌਲਿਊਮ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣਾ ਹੈ?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।\n\n ਵਰਤਮਾਨ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ > ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ਖਾਲੀ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ਸ਼ਾਰਟਕੱਟਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ਰੱਦ ਕਰੋ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ਸ਼ਾਰਟਕੱਟ ਬੰਦ ਕਰੋ"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਐਪ ਫਿਲਹਾਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਇਸਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ਹੋਰ ਜਾਣੋ"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"ਕੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰਨੀ ਹੈ?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ਤੁਹਾਡੀਆਂ ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ, ਸੂਚਨਾਵਾਂ, ਡਾਟਾ ਅਤੇ ਹੋਰ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ਇਹ ਐਪ Android ਦੇ ਕਿਸੇ ਵਧੇਰੇ ਪੁਰਾਣੇ ਵਰਜਨ ਲਈ ਬਣਾਈ ਗਈ ਸੀ ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ। ਅੱਪਡੇਟਾਂ ਲਈ ਜਾਂਚ ਕਰੋ ਜਾਂ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ਡੀਵਾਈਸ ਲੋੜੀਂਦਾ ਚਾਰਜ ਹੈ। ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਹੁਣ ਪ੍ਰਤਿਬੰਧਿਤ ਨਹੀਂ ਹਨ।"</string> <string name="mime_type_folder" msgid="2203536499348787650">"ਫੋਲਡਰ"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ਐਪਲੀਕੇਸ਼ਨ"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ਫ਼ਾਈਲ"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਸਪਰੈੱਡਸ਼ੀਟ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ਪੇਸ਼ਕਾਰੀ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਪੇਸ਼ਕਾਰੀ"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ਫ਼ਾਈਲ</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 5f94b185e427..94fd851f7c66 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcje tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcje Androida TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"dostęp do kalendarza"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"wysyłanie i wyświetlanie SMS‑ów"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Pliki i multimedia"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"dostęp do zdjęć, multimediów i plików na Twoim urządzeniu"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"nagrywanie dźwięku"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Obsługuje kliknięcia, przesunięcia, ściągnięcia palców i inne gesty."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesty związane z odciskiem palca"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Może przechwytywać gesty wykonywane na czytniku linii papilarnych w urządzeniu."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Robienie zrzutu ekranu"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Może robić zrzuty ekranu wyświetlacza."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"wyłączanie lub zmienianie paska stanu"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"działanie jako pasek stanu"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Gdy skrót jest włączony, jednoczesne naciśnięcie przez trzy sekundy obu klawiszy sterowania głośnością uruchomi funkcję ułatwień dostępu.\n\nBieżąca funkcja ułatwień dostępu:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nFunkcję możesz zmienić, wybierając Ustawienia > Ułatwienia dostępu."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Puste"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edytuj skróty"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anuluj"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Wyłącz skrót"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacja niedostępna"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie jest teraz dostępna. Zarządza tym aplikacja <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Więcej informacji"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil służbowy?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacje do pracy, powiadomienia, dane i inne funkcje profilu do pracy zostaną włączone"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacja jest na starszą wersję Androida i może nie działać prawidłowo. Sprawdź dostępność aktualizacji lub skontaktuj się z programistą."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sprawdź dostępność aktualizacji"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Masz nowe wiadomości"</string> @@ -2033,14 +2031,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Oszczędzanie baterii"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Oszczędzanie baterii zostało wyłączone"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon jest wystarczająco naładowany. Funkcje nie są już ograniczone."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tablet jest wystarczająco naładowany. Funkcje nie są już ograniczone."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Urządzenie jest wystarczająco naładowane. Funkcje nie są już ograniczone."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Folder"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplikacja na Androida"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Plik"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Arkusz kalkulacyjny <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacja"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Prezentacja <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth pozostanie włączony w trybie samolotowym"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Ładuję"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="few"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> pliki</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Przełącz podzielony ekran"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 567d6d4ba476..72a3ce904a8c 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Limpar"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string> - <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Planilha em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Apresentação"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> arquivo</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index b746c923a4d9..4f45517c0bb9 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a aplicação de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade.\n\n Funcionalidade de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pode alterar a funcionalidade em Definições > Acessibilidade."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Esvaziar"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"A aplicação não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicação <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível neste momento. A aplicação <xliff:g id="APP_NAME_1">%2$s</xliff:g> gere esta definição."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"As aplicações de trabalho, as notificações, os dados e outras funcionalidades do perfil de trabalho serão desativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string> - <string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicação foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar se existem atualizações"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Folha de cálculo <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Apresentação"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth continuará ativado durante o modo de avião."</string> <string name="car_loading_profile" msgid="8219978381196748070">"A carregar…"</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> ficheiros</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar/desativar o ecrã dividido"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecrã de bloqueio"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de ecrã"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 567d6d4ba476..72a3ce904a8c 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Limpar"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string> - <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Este app foi criado para uma versão mais antiga do Android e pode não funcionar corretamente. Tente verificar se há atualizações ou entre em contato com o desenvolvedor."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Procurar atualizações"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Você tem mensagens novas"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Planilha em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Apresentação"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Apresentação em <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá ativado no modo avião"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Carregando"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> arquivo</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 5b1153750547..d7cdade6c674 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Eu"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opțiuni tablet PC"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opțiuni pentru Android TV"</string> @@ -290,8 +294,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acceseze calendarul"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"trimită și să vadă mesajele SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Fișiere și media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"acceseze fotografiile, conținutul media și fișierele de pe dispozitiv"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Microfon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"înregistreze sunet"</string> @@ -317,10 +320,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Poate atinge, glisa, ciupi sau folosi alte gesturi."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gesturi ce implică amprente"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Poate reda gesturile făcute pe senzorul de amprentă al dispozitivului."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Faceți o captură de ecran"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Poate face o captură de ecran."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"dezactivare sau modificare bare de stare"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"să fie bara de stare"</string> @@ -1637,7 +1638,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de 3 secunde, veți lansa o funcție de accesibilitate.\n\n Funcția actuală de accesibilitate:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puteți schimba funcția în Setări > Accesibilitate."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Goliți"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editați comenzile rapide"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulați"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Dezactivați comanda rapidă"</string> @@ -1882,13 +1882,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplicația nu este disponibilă"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Momentan, aplicația <xliff:g id="APP_NAME_0">%1$s</xliff:g> nu este disponibilă. Aceasta este gestionată de <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Aflați mai multe"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Activați profilul de serviciu?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Se vor activa aplicațiile dvs. de serviciu, notificările, datele și alte funcții ale profilului de serviciu"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Activați"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Această aplicație a fost creată pentru o versiune Android mai veche și este posibil să nu funcționeze corect. Încercați să căutați actualizări sau contactați dezvoltatorul."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Căutați actualizări"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Aveți mesaje noi"</string> @@ -2000,14 +1998,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria se poate descărca înainte de încărcarea obișnuită"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Economisirea bateriei este activată pentru a prelungi durata de funcționare a bateriei"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Economisirea bateriei"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Economisirea bateriei a fost dezactivată"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefonul este încărcat suficient. Funcțiile nu mai sunt limitate."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tableta este încărcată suficient. Funcțiile nu mai sunt limitate."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Dispozitivul este încărcat suficient. Funcțiile nu mai sunt limitate."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Dosar"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplicație Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Fișier"</string> @@ -2026,6 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Foaie de calcul <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentare"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Prezentare <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Conexiunea Bluetooth va rămâne activată în modul Avion"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Se încarcă"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="few"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fișiere</item> @@ -2044,5 +2039,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activați ecranul împărțit"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index fa283d82b209..91b7ca6ab62c 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Настройки планшетного ПК"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Настройки Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"доступ к календарю"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"отправлять и просматривать SMS-сообщения"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы и медиафайлы"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"записывать аудио"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Может выполнять жесты нажатия, пролистывания, масштабирования и т. д."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Регистрировать жесты на сканере отпечатков пальцев"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Использовать сканер отпечатков пальцев для дополнительных жестов."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Создавать скриншоты"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Создавать скриншоты экрана."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"Отключение/изменение строки состояния"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Приложение сможет отключать строку состояния, а также добавлять и удалять системные значки."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"Замена строки состояния"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Использовать быстрое включение?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте три секунды обе кнопки регулировки громкости.\n\nТекущая функция специальных возможностей:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nВы можете изменить ее в разделе \"Настройки > Специальные возможности\"."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Очистить"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменить быстрые клавиши"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отмена"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Деактивировать быстрое включение"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Приложение недоступно"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Приложение \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" недоступно. Его работу ограничивает приложение \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Подробнее"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Включить рабочий профиль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Будут включены корпоративные приложения, уведомления, данные и другие функции рабочего профиля."</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Включить"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Это приложение было создано для более ранней версии Android и может работать со сбоями. Проверьте наличие обновлений или свяжитесь с разработчиком."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Проверить обновления"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Новые сообщения"</string> @@ -2033,14 +2031,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Устройство заряжено достаточно. Функции больше не ограничены."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Папка"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Приложение Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Таблица <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентация"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Презентация <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth будет работать в режиме полета."</string> <string name="car_loading_profile" msgid="8219978381196748070">"Загрузка"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one">\"<xliff:g id="FILE_NAME_2">%s</xliff:g>\" и ещё <xliff:g id="COUNT_3">%d</xliff:g> файл</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Включить или выключить разделение экрана"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 3899cd79c62d..601f9b9ee6c6 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string> <string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"මම"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ටැබ්ලට විකල්ප"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV විකල්ප"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ඔබේ දින දර්ශනයට පිවිසෙන්න"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"කෙටි පණිවිඩ"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS පණිවිඩ යැවීම සහ බැලීම"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ගොනු සහ මාධ්ය"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"ඔබේ උපාංගයේ ඇති ඡායාරූප, මාධ්ය සහ ගොනුවලට පිවිසීම"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"මයික්රොෆෝනය"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ශ්රව්ය පටිගත කරන්න"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"තට්ටු කිරීමට, ස්වයිප් කිරීමට, පින්ච් කිරීමට, සහ වෙනත් අභින සිදු කිරීමට හැකිය."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ඇඟිලි සලකුණු ඉංගිත"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"උපාංගයෙහි ඇඟිලි සලකුණු සංවේදකය මත සිදු කරන ඉංගිත ග්රහණය කළ හැකිය."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"තිර රුව ගන්න"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"සංදර්ශකයේ තිර රුවක් ගැනීමට හැකිය."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"තත්ව තීරුව අබල කරන්න හෝ වෙනස් කරන්න"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"තත්ව තීරුව අක්රිය කිරීමට හෝ පද්ධති නිරූපක එකතු හෝ ඉවත් කිරීමට යෙදුමට අවසර දේ."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"තත්ත්ව තීරුව බවට පත්වීම"</string> @@ -1617,7 +1618,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ප්රවේශ්යතා කෙටිමඟ භාවිතා කරන්නද?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"කෙටිමඟ සක්රිය විට, හඬ බොත්තම් දෙකම තත්පර 3ක් අල්ලාගෙන සිටීමෙන් ප්රවේශ්යත අංගයක් ඇරඹේ.\n\n වත්මන් ප්රවේශ්යතා අංගය:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n සැකසීම් > ප්රවේශ්යතාව තුළ ඔබට අංගය වෙනස් කළ හැක."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"හිස්"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"කෙටිමං සංස්කරණ කරන්න"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"අවලංගු කරන්න"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"කෙටිමඟ ක්රියාවිරහිත කරන්න"</string> @@ -1852,13 +1852,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"යෙදුම නොතිබේ"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> මේ අවස්ථාවේදී ලබා ගත නොහැකිය. මෙය <xliff:g id="APP_NAME_1">%2$s</xliff:g> මගින් කළමනාකරණය කෙරේ."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"තව දැන ගන්න"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"කාර්යාල පැතිකඩ ක්රියාත්මක කරන්නද?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ඔබගේ වැඩ යෙදුම්, දැනුම්දීම්, දත්ත සහ වෙනත් කාර්යාල පැතිකඩ විශේෂාංග ක්රියාත්මක කරනු ඇත"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ක්රියාත්මක කරන්න"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"මෙම යෙදුම Android හි පැරණි අනුවාදයක් සඳහා තනා ඇති අතර නිසියාකාරව ක්රියා නොකරනු ඇත. යාවත්කාලීන සඳහා පරික්ෂා කිරීම උත්සාහ කරන්න, නැතහොත් සංවර්ධක අමතන්න."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"යාවත්කාලීන සඳහා පරික්ෂා කරන්න"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ඔබට නව පණිවිඩ තිබේ"</string> @@ -1969,14 +1967,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"උපාංගයට ප්රමාණවත් ආරෝපණයක් තිබේ. විශේෂාංග තවදුරටත් සීමා කර නැත."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ෆෝල්ඩරය"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android යෙදුම"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ගොනුව"</string> @@ -1995,6 +1989,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> පැතුරුම්පත"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ඉදිරිපත් කිරීම"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ඉදිරිපත් කිරීම"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"බ්ලූටූත් ගුවන් යානා ප්රකාරය තුළ ක්රියාත්මකව පවතිනු ඇත"</string> <string name="car_loading_profile" msgid="8219978381196748070">"පූරණය කරමින්"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one">ගොනු<xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g></item> @@ -2012,5 +2007,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"බෙදුම් තිරය ටොගල කරන්න"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f48368f5ccd6..fb81855b4590 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ja"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zariadenia Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"prístup ku kalendáru"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"posielanie a zobrazovanie SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Súbory a médiá"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"prístup k fotkám, médiám a súborom v zariadení"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofón"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"nahrávanie zvuku"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Je možné použiť klepnutie, prejdenie, stiahnutie prstami a ďalšie gestá."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestá odtlačkom prsta"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Dokáže zaznamenať gestá na senzore odtlačkov prstov zariadenia."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Vytvoriť snímku obrazovky"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Je možné vytvoriť snímku obrazovky."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"zakázanie alebo zmeny stavového riadka"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Umožňuje aplikácii vypnúť stavový riadok alebo pridať a odstrániť systémové ikony."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"vydávanie sa za stavový riadok"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti.\n\n Aktuálna funkcia dostupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciu môžete zmeniť v časti Nastavenia > Dostupnosť."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prázdne"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upraviť skratky"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušiť"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnúť skratku"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikácia nie je k dispozícii"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie je momentálne k dispozícii. Spravuje to aplikácia <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Ďalšie informácie"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Zapnúť pracovný profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Pracovné aplikácie, upozornenia, dáta a ďalšie funkcie pracovného profilu sa zapnú"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Táto aplikácia bola zostavená pre staršiu verziu Androidu a nemusí správne fungovať. Skúste skontrolovať dostupnosť aktualizácií alebo kontaktovať vývojára."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Skontrolovať dostupnosť aktualizácie"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové správy."</string> @@ -2033,14 +2031,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batéria sa môže vybiť pred obvyklým nabitím"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bol aktivovaný šetrič batérie na predĺženie výdrže batérie"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Šetrič batérie"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Šetrič batérie bol vypnutý."</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefón je dostatočne nabitý. Funkcie už nie sú obmedzené."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tablet je dostatočne nabitý. Funkcie už nie sú obmedzené."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Zariadenie je dostatočne nabité. Funkcie už nie sú obmedzené."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Priečinok"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplikácia pre Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Súbor"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Tabuľka <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezentácia"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Prezentácia <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Rozhranie Bluetooth zostane počas režimu v lietadle zapnuté"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Načítava sa"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="few"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> súbory</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Prepnúť rozdelenú obrazovku"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 6343e0efc7ea..9405fb2a4e13 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Jaz"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabličnega računalnika"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti naprave Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"dostop do koledarja"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"pošiljanje in ogled sporočil SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Datoteke in predstavnost"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"dostop do fotografij, predstavnosti in datotek v napravi"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"snemanje zvoka"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Mogoče je izvajanje dotikov, vlečenja, primikanja in razmikanja prstov ter drugih potez."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Poteze po tipalu prstnih odtisov"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Prepoznava poteze, narejene po tipalu prstnih odtisov naprave."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ustvarjanje posnetka zaslona"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Lahko naredi posnetek zaslona."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"onemogočanje ali spreminjanje vrstice stanja"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Aplikacijam omogoča onemogočenje vrstice stanja ali dodajanje in odstranjevanje ikon sistema."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"postane vrstica stanja"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami.\n\n Trenutna funkcija za ljudi s posebnimi potrebami:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkcijo lahko spremenite v »Nastavitve > Funkcije za ljudi s posebnimi potrebami«."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Prazno"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi bližnjice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Prekliči"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izklopi bližnjico"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacija ni na voljo"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno ni na voljo. To upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Več o tem"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Želite vklopiti delovni profil?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Vklopili boste svoje delovne aplikacije, obvestila, podatke in druge funkcije delovnega profila"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Vklop"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ta aplikacija je bila zasnovana za starejšo različico Androida in morda ne bo delovala pravilno. Preverite, ali so na voljo posodobitve, ali pa se obrnite na razvijalca."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Preveri, ali je na voljo posodobitev"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Imate nova sporočila."</string> @@ -2033,14 +2031,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulator se bo morda izpraznil, preden ga običajno priključite na polnjenje"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo akumulatorja za podaljšanje časa delovanja akumulatorja"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo akumulatorja"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Varčevanje z energijo baterije je izklopljeno"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija v telefonu je dovolj napolnjena. Funkcije niso več omejene."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Baterija v tabličnem računalniku je dovolj napolnjena. Funkcije niso več omejene."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Baterija v napravi je dovolj napolnjena. Funkcije niso več omejene."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Mapa"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplikacija za Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Datoteka"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Preglednica <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Predstavitev"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Predstavitev <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth bo v načinu za letalo ostal vklopljen"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Nalaganje"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> in še <xliff:g id="COUNT_3">%d</xliff:g> datoteka</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Preklop razdeljenega zaslona"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index ceba0be195f2..fe167da393fa 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Unë"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsionet e tabletit"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsionet e Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"qasje te kalendari yt"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"dërgo dhe shiko mesazhet SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Skedarët dhe media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"qasjen te fotografitë, përmbajtjet audio-vizuale dhe skedarët në pajisje"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofoni"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"regjistro audio"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gjestet e gjurmës së gishtit"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Mund të regjistrojë gjestet e kryera në sensorin e gjurmës së gishtit të pajisjes."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Nxirr një pamje të ekranit"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Mund të nxirret një pamje e ekranit."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"çaktivizo ose modifiko shiritin e statusit"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"të bëhet shiriti i statusit"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie.\n\n Funksioni aktual i qasshmërisë:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Mund ta ndryshosh funksionin te Cilësimet > Qasshmëria."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Boshatis"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redakto shkurtoret"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulo"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Çaktivizo shkurtoren"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Aplikacioni nuk ofrohet"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> nuk ofrohet në këtë moment. Kjo menaxhohet nga <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Mëso më shumë"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Të aktivizohet profili i punës?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacionet e punës, njoftimet, të dhënat e tua dhe funksionet e tjera të profilit të punës do të aktivizohen"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ky aplikacion është ndërtuar për një version më të vjetër të Android dhe mund të mos funksionojë mirë. Provo të kontrollosh për përditësime ose kontakto me zhvilluesin."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kontrollo për përditësim"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Ke mesazhe të reja"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"\"Kursyesi i baterisë\" u aktivizua për të zgjatur jetëgjatësinë e baterisë"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Kursyesi i baterisë"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"\"Kursyesi i baterisë\" është çaktivizuar"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefoni ka nivel të mjaftueshëm baterie. Funksionet nuk janë më të kufizuara."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tableti ka nivel të mjaftueshëm baterie. Funksionet nuk janë më të kufizuara."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Pajisja ka nivel të mjaftueshëm baterie. Funksionet nuk janë më të kufizuara."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Dosje"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Aplikacion i Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Skedar"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Fletëllogaritëse <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Prezantim"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Prezantim <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth-i do të qëndrojë i aktivizuar gjatë modalitetit të aeroplanit"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Po ngarkohet"</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> skedarë</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Kalo tek ekrani i ndarë"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index f3a2ce532df5..564612c454ce 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -196,6 +196,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ја"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опције за таблет"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опције Android TV-а"</string> @@ -1634,7 +1638,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Желите ли да користите пречицу за приступачност?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности.\n\n Актуелна функција приступачности:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцију у одељку Подешавања > Приступачност."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Празно"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Измените пречице"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Откажи"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Искључи пречицу"</string> @@ -1879,11 +1882,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Апликација није доступна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Апликација <xliff:g id="APP_NAME_0">%1$s</xliff:g> тренутно није доступна. <xliff:g id="APP_NAME_1">%2$s</xliff:g> управља доступношћу."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Сазнајте више"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо профил за Work?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције профила за Work"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ова апликација је направљена за старију верзију Android-а, па можда неће радити исправно. Потражите ажурирања или контактирајте програмера."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Потражи ажурирање"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Имате нове поруке"</string> @@ -2017,6 +2020,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> табела"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентација"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> презентација"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth остаје укључен током режима рада у авиону"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Учитава се"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> и још <xliff:g id="COUNT_3">%d</xliff:g> датотека</item> @@ -2035,5 +2039,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Укључите/искључите подељени екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index ade5e6af081a..4332352909f6 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Jag"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Alternativ för surfplattan"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Alternativ för Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder.\n\n Aktuell tillgänglighetsfunktion:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan ändra funktionen i Inställningar > Tillgänglighet."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Töm"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redigera genvägar"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Inaktivera kortkommandot"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Appen är inte tillgänglig"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> är inte tillgänglig just nu. Detta hanteras av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Läs mer"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Vill du aktivera jobbprofilen?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappar, aviseringar, data och andra funktioner i jobbprofilen aktiveras"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string> - <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Appen har utvecklats för en äldre version av Android och kanske inte fungerar som den ska. Testa att söka efter uppdateringar eller kontakta utvecklaren."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Sök efter uppdateringar"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Du har nya meddelanden"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g>-kalkylark"</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 fortsätter att vara på i flygplansläget"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Läser in"</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> filer</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktivera och inaktivera delad skärm"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmdump"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index f893af3ca2f2..d1bff3f55906 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mimi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Chaguo za kompyuta ndogo"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Chaguo za Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ifikie kalenda yako"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"itume na iangalie SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <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">"Kipokea sauti"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"irekodi sauti"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Unaweza kugusa, kutelezesha kidole, kubana na kutekeleza ishara zingine."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Ishara za alama ya kidole"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Inaweza kurekodi ishara zinazotekelezwa kwenye kitambua alama ya kidole."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Piga picha ya skrini"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Inaweza kupiga picha ya skrini ya onyesho."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"zima au rekebisha mwambaa hali"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa aikoni za mfumo."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"kuwa sehemu ya arifa"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha ufikivu.\n\n Kipengele cha ufikivu kilichopo kwa sasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio > Zana za ufikivu."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Tupu"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kubadilisha njia za mkato"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ghairi"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Zima kipengele cha Njia ya Mkato"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Programu haipatikani"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> haipatikani kwa sasa. Inasimamiwa na <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Pata maelezo zaidi"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ungependa kuwasha wasifu wa kazini?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini, arifa na vipengele vingine vya wasifu wa kazini"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Programu hii iliundwa kwa ajili ya toleo la zamani la Android na huenda isifanye kazi vizuri. Jaribu kuangalia masasisho au uwasiliane na msanidi programu."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Angalia masasisho"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Una ujumbe mpya"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Huenda betri itakwisha chaji mapema"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Kiokoa betri"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Kiokoa Betri kimezimwa"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Simu ina chaji ya kutosha. Vipengele havizuiliwi tena."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Kompyuta kibao ina chaji ya kutosha. Vipengele havizuiliwi tena."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Kifaa kina chaji ya kutosha. Vipengele havizuiliwi tena."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Folda"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Programu ya Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Faili"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Lahajedwali la <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Wasilisho"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Wasilisho la <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth haitazima katika hali ya ndegeni"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Inapakia"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="other">Faili <xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g></item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Geuza Skrini Iliyogawanywa"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index d3a461303f1d..5444f36081f3 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string> <string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"நான்"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"டேப்லெட் விருப்பங்கள்"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV விருப்பத்தேர்வுகள்"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"கேலெண்டரை அணுகலாம்"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS அனுப்பலாம், வந்த SMSகளைப் பார்க்கலாம்"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ஃபைல்களும் மீடியாவும்"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுக வேண்டும்"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"மைக்ரோஃபோன்"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ஒலிப் பதிவு செய்யலாம்"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"தட்டலாம், ஸ்வைப் செய்யலாம், பின்ச் செய்யலாம் மற்றும் பிற சைகைகளைச் செயல்படுத்தலாம்."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"கைரேகை சைகைகள்"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"சாதனத்தின் கைரேகை சென்சார்மேல் செய்யப்படும் சைகைகளைக் கேப்ட்சர் செய்ய முடியும்."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ஸ்கிரீன்ஷாட்டை எடுக்கும்"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"டிஸ்ப்ளேவை ஸ்கிரீன்ஷாட் எடுக்க முடியும்."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"நிலைப் பட்டியை முடக்குதல் அல்லது மாற்றுதல்"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"நிலைப் பட்டியை முடக்க அல்லது முறைமையில் ஐகான்களைச் சேர்க்க மற்றும் அகற்ற ஆப்ஸை அனுமதிக்கிறது."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"நிலைப் பட்டியில் இருக்கும்"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"ஷார்ட்கட் இயக்கத்தில் இருந்தால், இரண்டு ஒலியளவு பொத்தான்களையும் 3 வினாடிகள் அழுத்தி, அணுகல்தன்மை அம்சத்தை இயக்கலாம்.\n\n தற்போதைய அணுகல்தன்மை அம்சம்:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n அமைப்புகள் > அணுகல்தன்மை என்பதற்குச் சென்று, அம்சத்தை மாற்றலாம்."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"காலியானது"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ஷார்ட்கட்களை மாற்று"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ரத்துசெய்"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ஷார்ட்கட்டை முடக்கு"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ஆப்ஸை உபயோகிக்க இயலாது"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"இப்போது <xliff:g id="APP_NAME_0">%1$s</xliff:g> ஆப்ஸை உபயோகிக்க இயலாது. இதை <xliff:g id="APP_NAME_1">%2$s</xliff:g> நிர்வகிக்கிறது."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"மேலும் அறிக"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"பணிச் சுயவிவரத்தை ஆன் செய்யவா?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"பணி ஆப்ஸ், அறிவிப்புகள், தரவு மற்றும் பிற பணிச் சுயவிவர அம்சங்கள் ஆன் செய்யப்படும்"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"இயக்கு"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"இந்த ஆப்ஸ் Android இன் பழைய பதிப்புக்காக உருவாக்கப்பட்டதால், சரியாக வேலை செய்யாமல் போகலாம். புதுப்பிப்புகள் ஏதேனும் உள்ளதா எனப் பார்க்கவும் அல்லது டெவெலப்பரைத் தொடர்புகொள்ளவும்."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"புதுப்பிப்பு உள்ளதா எனப் பார்"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"புதிய செய்திகள் வந்துள்ளன"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"சாதனத்தில் போதுமான சார்ஜ் உள்ளது. அம்சங்கள் இனி தடையின்றி இயங்கும்."</string> <string name="mime_type_folder" msgid="2203536499348787650">"கோப்புறை"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ஆப்ஸ்"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ஃபைல்"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> விரிதாள்"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"விளக்கக்காட்சி"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> விளக்கக்காட்சி"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"விமானப் பயன்முறையில் இருக்கும்போதும் புளூடூத் ஆன் செய்யப்பட்டே இருக்கும்"</string> <string name="car_loading_profile" msgid="8219978381196748070">"ஏற்றுகிறது"</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> ஃபைல்கள்</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"திரைப் பிரிப்பை நிலைமாற்று"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 04a4d417407d..f9f6479eece2 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string> <string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"నేను"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"టాబ్లెట్ ఎంపికలు"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ఎంపికలు"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్ను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ఫైల్స్ మరియు మీడియా"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్లను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"మైక్రోఫోన్"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ఆడియోను రికార్డ్ చేయడానికి"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"నొక్కగలరు, స్వైప్ చేయగలరు, స్క్రీన్పై రెండు వేళ్లను ఉంచి ఆ వేళ్లను దగ్గరకు లేదా దూరానికి లాగగలరు మరియు ఇతర సంజ్ఞలను చేయగలరు."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"వేలిముద్ర సంజ్ఞలు"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"పరికర వేలిముద్ర సెన్సార్లో ఉపయోగించిన సంజ్ఞలను క్యాప్చర్ చేయవచ్చు."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"స్క్రీన్షాట్ను తీయండి"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"డిస్ప్లే యొక్క స్క్రీన్షాట్ తీసుకోవచ్చు."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"స్థితి బార్ను నిలిపివేయడం లేదా సవరించడం"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"స్థితి బార్ను నిలిపివేయడానికి లేదా సిస్టమ్ చిహ్నాలను జోడించడానికి మరియు తీసివేయడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"స్థితి పట్టీగా ఉండటం"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్కట్ను ఉపయోగించాలా?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"షార్ట్కట్ ఆన్లో ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కితే యాక్సెస్ సామర్థ్య ఫీచర్ ప్రారంభం అవుతుంది.\n\n ప్రస్తుత యాక్సెస్ సామర్థ్య ఫీచర్:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n సెట్టింగ్లు > యాక్సెస్ సామర్థ్యంలో మీరు ఫీచర్ను మార్చవచ్చు."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ఖాళీ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"షార్ట్కట్లను ఎడిట్ చేయి"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"రద్దు చేయి"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"యాప్ అందుబాటులో లేదు"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు. ఇది <xliff:g id="APP_NAME_1">%2$s</xliff:g> ద్వారా నిర్వహించబడుతుంది."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"మరింత తెలుసుకోండి"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"కార్యాలయ ప్రొఫైల్ని ఆన్ చేయాలా?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"మీ కార్యాలయ యాప్లు, నోటిఫికేషన్లు, డేటా మరియు ఇతర కార్యాలయ ప్రొఫైల్ ఫీచర్లు ఆన్ చేయబడతాయి"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"ఆన్ చేయి"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్డేట్ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్ని సంప్రదించండి."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్డేట్ కోసం తనిఖీ చేయండి"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"పరికరానికి తగినంత ఛార్జింగ్ ఉంది. ఫీచర్లు ఇప్పటి నుండి పరిమితం చేయబడవు."</string> <string name="mime_type_folder" msgid="2203536499348787650">"ఫోల్డర్"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android అప్లికేషన్"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ఫైల్"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> స్ప్రెడ్షీట్"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ప్రదర్శన"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ప్రదర్శన"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"లోడవుతోంది"</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> ఫైల్లు</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"స్క్రీన్ విభజనను టోగుల్ చేయి"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 11aa4076eea4..7796b03b1ae0 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"ฉัน"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ตัวเลือกของแท็บเล็ต"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"ตัวเลือกของ Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"เข้าถึงปฏิทิน"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"ส่งและดูข้อความ SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"ไฟล์และสื่อ"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"เข้าถึงรูปภาพ สื่อ และไฟล์บนอุปกรณ์ของคุณ"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"ไมโครโฟน"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"บันทึกเสียง"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"สามารถแตะ เลื่อน บีบ และทำท่าทางสัมผัสอื่นๆ"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"ท่าทางสัมผัสลายนิ้วมือ"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"สามารถจับท่าทางสัมผัสที่เกิดขึ้นบนเซ็นเซอร์ลายนิ้วมือของอุปกรณ์"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"ถ่ายภาพหน้าจอ"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ถ่ายภาพหน้าจอได้"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"ปิดการใช้งานหรือแก้ไขแถบสถานะ"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"อนุญาตให้แอปพลิเคชันปิดใช้งานแถบสถานะหรือเพิ่มและนำไอคอนระบบออก"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"เป็นแถบสถานะ"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ใช้ทางลัดการช่วยเหลือพิเศษไหม"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มเป็นเวลา 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ\n\n ฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n คุณสามารถเปลี่ยนฟีเจอร์ในการตั้งค่า > การช่วยเหลือพิเศษ"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"ล้าง"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"แก้ไขทางลัด"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ยกเลิก"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ปิดทางลัด"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"แอปไม่พร้อมใช้งาน"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"เปิด <xliff:g id="APP_NAME_0">%1$s</xliff:g> ไม่ได้ในขณะนี้ แอปนี้จัดการโดย <xliff:g id="APP_NAME_1">%2$s</xliff:g>"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"ดูข้อมูลเพิ่มเติม"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"เปิดโปรไฟล์งานไหม"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"ระบบจะเปิดแอปงาน การแจ้งเตือน ข้อมูล และฟีเจอร์อื่นๆ ในโปรไฟล์งาน"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"เปิด"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"แอปนี้สร้างขึ้นเพื่อ Android เวอร์ชันเก่าและอาจทำงานผิดปกติ โปรดลองตรวจหาการอัปเดตหรือติดต่อนักพัฒนาซอฟต์แวร์"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ตรวจสอบอัปเดต"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"คุณมีข้อความใหม่"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"อุปกรณ์มีแบตเตอรี่เพียงพอ ไม่มีการจำกัดฟีเจอร์แล้ว"</string> <string name="mime_type_folder" msgid="2203536499348787650">"โฟลเดอร์"</string> <string name="mime_type_apk" msgid="3168784749499623902">"ไฟล์แอปพลิเคชัน Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"ไฟล์"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"ไฟล์สเปรดชีต <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"ไฟล์งานนำเสนอ"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"ไฟล์งานนำเสนอ <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"บลูทูธจะเปิดอยู่ในโหมดบนเครื่องบิน"</string> <string name="car_loading_profile" msgid="8219978381196748070">"กำลังโหลด"</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> ไฟล์</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"เปิด/ปิดการแบ่งหน้าจอ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 718e170c56ec..d15bcd7f48d7 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ako"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Mga pagpipilian sa tablet"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Mga opsyon sa Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"i-access ang iyong kalendaryo"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"magpadala at tumingin ng mga mensaheng SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Mga file at media"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"i-access ang mga larawan, media at file sa iyong device"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikropono"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"mag-record ng audio"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"May kakayahang mag-tap, mag-swipe, mag-pinch at magsagawa ng iba pang mga galaw."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Mga galaw gamit ang fingerprint"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Makukunan ang mga galaw na ginawa sa sensor para sa fingerprint ng device."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Kumuha ng screenshot"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Puwedeng kumuha ng screenshot ng display."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"i-disable o baguhin ang status bar"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Pinapayagan ang app na i-disable ang status bar o magdagdag at mag-alis ng mga icon ng system."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"maging status bar"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting > Pagiging Accessible."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Bakantehin"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"I-edit ang mga shortcut"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselahin"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"I-off ang Shortcut"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Hindi available ang app"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Hindi available ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa ngayon. Pinamamahalaan ito ng <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Matuto pa"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"I-on ang profile sa trabaho?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Mao-on ang iyong mga app sa trabaho, notification, data, at iba pang feature sa profile sa trabaho"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ang app na ito ay ginawa para sa mas lumang bersyon ng Android at maaaring hindi gumana nang maayos. Subukang tingnan kung may mga update, o makipag-ugnayan sa developer."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Tingnan kung may update"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Mayroon kang mga bagong mensahe"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pangtipid sa Baterya para patagalin ang buhay ng baterya"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pangtipid sa Baterya"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pangtipid sa Baterya"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"May sapat na charge ang telepono. Hindi na pinaghihigpitan ang mga feature."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"May sapat na charge ang tablet. Hindi na pinaghihigpitan ang mga feature."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"May sapat na charge ang device. Hindi na pinaghihigpitan ang mga feature."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Folder"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android application"</string> <string name="mime_type_generic" msgid="4606589110116560228">"File"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> na 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> na presentation"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Mananatiling naka-on ang bluetooth habang nasa airplane mode"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Naglo-load"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> file</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"I-toggle ang Split Screen"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 93d9af10f570..e5559c507c30 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Ben"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet seçenekleri"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçenekleri"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"takviminize erişme"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS mesajları gönderme ve görüntüleme"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Dosyalar ve medya"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"cihazınızdaki fotoğraflara, medyaya ve dosyalara erişme"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ses kaydetme"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Dokunabilir, hızlıca kaydırabilir, sıkıştırabilir ve diğer hareketleri yapabilirsiniz."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Parmak izi hareketleri"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Cihazın parmak izi sensörlerinde gerçekleştirilen hareketleri yakalayabilir."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Ekran görüntüsü al"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Ekran görüntüsü alınabilir."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"durum çubuğunu devre dışı bırak veya değiştir"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"durum çubuğunda olma"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kısayol açık olduğunda, ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır.\n\n Geçerli erişilebilirlik özelliği:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Özelliği, Ayarlar > Erişilebilirlik seçeneğinden değiştirebilirsiniz."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Boş"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kısayolları düzenle"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"İptal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Kısayolu Kapat"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Uygulama kullanılamıyor"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulaması şu anda kullanılamıyor. Uygulamanın kullanım durumu <xliff:g id="APP_NAME_1">%2$s</xliff:g> tarafından yönetiliyor."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Daha fazla bilgi"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"İş profili açılsın mı?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"İş uygulamalarınız, bildirimleriniz, verileriniz ve diğer iş profili özellikleriniz açılacak"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu uygulama Android\'in daha eski bir sürümü için oluşturuldu ve düzgün çalışmayabilir. Güncellemeleri kontrol etmeyi deneyin veya geliştiriciyle iletişime geçin."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Güncellemeleri denetle"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Yeni mesajlarınız var"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pil normal şarjdan önce bitebilir"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Pilin ömrünü uzatmak için Pil Tasarrufu etkinleştirildi"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pil Tasarrufu"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Pil Tasarrufu kapatıldı"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefon yeterince şarj oldu. Özellikler artık kısıtlanmış değil."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Tablet yeterince şarj oldu. Özellikler artık kısıtlanmış değil."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Cihaz yeterince şarj oldu. Özellikler artık kısıtlanmış değil."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Klasör"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android uygulaması"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Dosya"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> e-tablo dosyası"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Sunu"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> sunu dosyası"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Uçak modunda Bluetooth açık kalacak"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Yükleniyor"</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> dosya</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekranı aç/kapat"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 0f8b3682c12a..7c06892e070c 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -198,6 +198,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Я"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Парам. пристрою"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Опції Android TV"</string> @@ -293,8 +297,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"отримувати доступ до календаря"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"надсилати та переглядати SMS-повідомлення"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файли й мультимедіа"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"отримувати доступ до фотографій, мультимедійного вмісту та файлів на вашому пристрої"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Мікрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"записувати аудіо"</string> @@ -320,10 +323,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Можна торкатися, проводити пальцем, стискати пальці та виконувати інші жести."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Жести на сканері відбитків пальців"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Може фіксувати жести на сканері відбитків пальців."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Робити знімки екрана"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Може робити знімки екрана."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"вимикати чи змін. рядок стану"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Дозволяє програмі вимикати рядок стану чи додавати та видаляти піктограми системи."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"відображатися як рядок стану"</string> @@ -1659,7 +1660,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Використовувати швидке ввімкнення?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Коли ярлик увімкнено, після натискання обох клавіш гучності й утримування їх протягом 3 секунд увімкнеться функція спеціальних можливостей.\n\n Поточна функція спеціальних можливостей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Цю функцію можна змінити в меню \"Налаштування\" > \"Спеціальні можливості\"."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Очистити"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редагувати засоби"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасувати"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Вимкнути ярлик"</string> @@ -1914,13 +1914,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Додаток недоступний"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> зараз недоступний. Керує додаток <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Докладніше"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Увімкнути робочий профіль?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Додатки, сповіщення, дані й інші функції робочого профілю буде ввімкнено"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Увімкнути"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Цей додаток створений для старішої версії Android і може працювати неналежним чином. Спробуйте знайти оновлення або зв’яжіться з розробником."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шукати оновлення"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"У вас є нові повідомлення"</string> @@ -2033,14 +2031,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Пристрій має достатньо заряду акумулятора. Функції вже не обмежено."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Папка"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Додаток Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Файл"</string> @@ -2059,6 +2053,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Таблиця у форматі <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Презентація"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Презентація у форматі <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"У режимі польоту Bluetooth залишатиметься ввімкненим"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Завантаження"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> і ще <xliff:g id="COUNT_3">%d</xliff:g> файл</item> @@ -2078,5 +2073,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Розділити екран"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 5b9571597cba..1b007200def6 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string> <string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"میں"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"ٹیبلیٹ کے اختیارات"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV اختیارات"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"اپنے کیلنڈر تک رسائی حاصل کریں"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS پیغامات بھیجیں اور دیکھیں"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"فائلز اور میڈیا"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"آپ کے آلہ پر تصاویر، میڈیا اور فائلوں تک رسائی حاصل کر سکتی ہیں"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"مائکروفون"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"آڈیو ریکارڈ کریں"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"تھپتھپانا، سوائپ کرنا، چٹکی بھرنا اور دیگر اشارے انجام دے سکتی ہے"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"فنگر پرنٹ کے اشارے"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"آلہ کے فنگر پرنٹ سینسر پر کیے گئے اشاروں کو کیپچر کر سکتا ہے۔"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"اسکرین شاٹ لیں"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"ڈسپلے کا اسکرین شاٹ لیا جا سکتا ہے۔"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"اسٹیٹس بار کو غیر فعال یا اس میں ترمیم کریں"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"ایپ کو اسٹیٹس بار غیر فعال کرنے یا سسٹم آئیکنز شامل کرنے اور ہٹانے کی اجازت دیتا ہے۔"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"بطور اسٹیٹس بار کام لیں"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ایکسیسبیلٹی شارٹ کٹ استعمال کریں؟"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔\n\n موجودہ ایکسیسبیلٹی خصوصیت:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n آپ خصوصیت کو ترتیبات > ایکسیسبیلٹی میں جا کر تبدیل کر سکتے ہیں۔"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"خالی"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"شارٹ کٹس میں ترمیم کریں"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"منسوخ کریں"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"شارٹ کٹ آف کریں"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"ایپ دستیاب نہیں ہے"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔ یہ <xliff:g id="APP_NAME_1">%2$s</xliff:g> کے زیر انتظام ہے۔"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"مزید جانیں"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"دفتری پروفائل آن کریں؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"آپ کی دفتری ایپس، اطلاعات، ڈیٹا اور دفتری پروفائل کی دیگر خصوصیات آن کر دی جائیں گی"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"آن کریں"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"یہ ایپ Android کے پرانے ورژن کے لئے بنائی گئی ہے اور ہو سکتا ہے صحیح طور پر کام نہ کرے۔ اپ ڈیٹس چیک کر کے آزمائیں یا ڈیولپر سے رابطہ کریں۔"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"اپ ڈیٹ چیک کریں"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"آپ کے پاس نئے پیغامات ہیں"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"آلہ میں کافی چارج ہے۔ خصوصیات پر اب پابندی نہیں ہے۔"</string> <string name="mime_type_folder" msgid="2203536499348787650">"فولڈر"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android ایپلیکیشن"</string> <string name="mime_type_generic" msgid="4606589110116560228">"فائل"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> اسپریڈشیٹ"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"پیشکش"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> پیشکش"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"لوڈ ہو رہا ہے"</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> فائلز</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"اسپلٹ اسکرین ٹوگل کریں"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index c83741468833..1193d278774d 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Men"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planshet sozlamalari"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV parametrlari"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\n Joriy maxsus imkoniyatlar funksiyasi:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bu funksiyani Sozlamalar > Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Boʻshatish"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Tezkor tugmalarni tahrirlash"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Bekor qilish"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Ilova ishlamayapti"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ishlamayapti. Uning ishlashini <xliff:g id="APP_NAME_1">%2$s</xliff:g> cheklamoqda."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Batafsil"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Ishchi profil yoqilsinmi?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ishchi ilovalar, bildirishnomalar, ma’lumotlar va boshqa ishchi profil imkoniyatlari yoqiladi"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string> - <string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Bu ilova eskiroq Android versiyalariga chiqarilgan va xato ishlashi mumkin. Yangilanishlarini tekshiring yoki dasturchi bilan bog‘laning."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Yangilanish borligini tekshirish"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Sizga yangi SMS keldi"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> jadval"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Taqdimot"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> taqdimot"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth parvoz rejimida yoniq qoladi"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Yuklanmoqda"</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> ta fayl</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ekranni ikkiga ajratish tugmasi"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 82662ab8f77f..7cfd87051a2b 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Tôi"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tùy chọn máy tính bảng"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Tùy chọn dành cho Android TV"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"truy cập lịch của bạn"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"Tin nhắn SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"gửi và xem tin nhắn SMS"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Tệp và nội dung nghe nhìn"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"truy cập ảnh, phương tiện và tệp trên thiết bị của bạn"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Micrô"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ghi âm"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Có thể nhấn, vuốt, chụm và thực hiện các cử chỉ khác."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Cử chỉ vân tay"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Có thể ghi lại các cử chỉ được thực hiện trên cảm biến vân tay của thiết bị."</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Chụp ảnh màn hình"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Có thể chụp ảnh màn hình."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"trở thành thanh trạng thái"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Khi phím tắt được bật, nhấn cả hai nút âm lượng trong 3 giây sẽ bắt đầu một tính năng trợ năng.\n\n Tính năng trợ năng hiện tại:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bạn có thể thay đổi tính năng trong Cài đặt > Trợ năng."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Xóa sạch"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Chỉnh sửa phím tắt"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hủy"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tắt phím tắt"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Ứng dụng không sử dụng được"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hiện không sử dụng được. Chính sách này do <xliff:g id="APP_NAME_1">%2$s</xliff:g> quản lý."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Tìm hiểu thêm"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Bạn muốn bật hồ sơ công việc?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Ứng dụng công việc, thông báo, dữ liệu và các tính năng khác của hồ sơ công việc sẽ được bật"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ứng dụng này được xây dựng cho một phiên bản Android cũ hơn và có thể hoạt động không bình thường. Hãy thử kiểm tra các bản cập nhật hoặc liên hệ với nhà phát triển."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra bản cập nhật"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string> @@ -1967,14 +1965,10 @@ <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pin có thể hết trước khi sạc bình thường"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Trình tiết kiệm pin được kích hoạt để kéo dài thời lượng pin"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Trình tiết kiệm pin"</string> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Trình tiết kiệm pin đã tắt"</string> + <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Điện thoại còn đủ pin. Các tính năng không bị hạn chế nữa."</string> + <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Máy tính bảng còn đủ pin. Các tính năng không bị hạn chế nữa."</string> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Thiết bị còn đủ pin. Các tính năng không bị hạn chế nữa."</string> <string name="mime_type_folder" msgid="2203536499348787650">"Thư mục"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Ứng dụng Android"</string> <string name="mime_type_generic" msgid="4606589110116560228">"Tệp"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"Bảng tính <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Bản trình bày"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"Bản trình bày <xliff:g id="EXTENSION">%1$s</xliff:g>"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth sẽ không tắt khi chế độ trên máy bay bật"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Đang tải"</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> tệp</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bật/tắt chế độ chia đôi màn hình"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 101a2eca8793..5d7ad5ad0361 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string> <string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"我"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板电脑选项"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 选项"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"访问您的日历"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"短信"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"发送和查看短信"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"文件和媒体"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"访问您设备上的照片、媒体内容和文件"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"麦克风"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"录制音频"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"可执行点按、滑动、双指张合等手势。"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"指纹手势"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"可以捕获在设备指纹传感器上执行的手势。"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"截取屏幕截图"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"可截取显示画面的屏幕截图。"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"停用或修改状态栏"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"允许应用停用状态栏或者增删系统图标。"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"用作状态栏"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用无障碍快捷方式吗?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"开启快捷方式后,同时按下两个音量按钮 3 秒钟即可启动所设定的无障碍功能。\n\n当前设定的无障碍功能:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如需更改设定的功能,请依次转到“设置”>“无障碍”。"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"清空"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"修改快捷方式"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"关闭快捷方式"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"应用无法使用"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>目前无法使用。该应用是由<xliff:g id="APP_NAME_1">%2$s</xliff:g>所管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"了解详情"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"要开启工作资料吗?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"您的工作应用、通知、数据及其他工作资料功能将会开启"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"开启"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此应用专为旧版 Android 打造,因此可能无法正常运行。请尝试检查更新或与开发者联系。"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"检查更新"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"您有新消息"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"设备电量充足。各项功能不再受限。"</string> <string name="mime_type_folder" msgid="2203536499348787650">"文件夹"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android 应用"</string> <string name="mime_type_generic" msgid="4606589110116560228">"文件"</string> @@ -1993,6 +1987,8 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> 电子表格"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"演示文稿"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> 演示文稿"</string> + <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) --> + <skip /> <string name="car_loading_profile" msgid="8219978381196748070">"正在加载"</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> 个文件</item> @@ -2010,5 +2006,13 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"开启/关闭分屏"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string> + <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) --> + <skip /> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 292986999e22..361eb4c66029 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"我本人"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"存取您的日曆"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"短訊"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"傳送和查看短訊"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"檔案及媒體"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"存取裝置上的相片、媒體和檔案"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"麥克風"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"錄音"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"可以輕按、滑動和兩指縮放,並執行其他手勢。"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"指紋手勢"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"可以擷取在裝置指紋感應器上執行的手勢。"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"擷取螢幕擷圖"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"可以擷取螢幕截圖。"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"停用或修改狀態列"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"成為狀態列"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙功能快速鍵嗎?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"快速鍵開啟後,同時按住音量按鈕 3 秒,無障礙功能便會啟用。\n\n目前的無障礙功能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如要變更功能,請前往「設定」>「無障礙功能」。"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"空白"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"關閉快速鍵"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"目前無法使用此應用程式"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用 <xliff:g id="APP_NAME_0">%1$s</xliff:g>。此應用程式是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作設定檔嗎?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟您的工作應用程式、通知、資料和其他工作設定檔功能"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"此應用程式專為舊版 Android 打造,因此可能無法正常運作。請嘗試檢查更新,或與開發人員聯絡。"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"您有新的訊息"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"裝置電量充足。各項功能已不再受限。"</string> <string name="mime_type_folder" msgid="2203536499348787650">"資料夾"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android 應用程式"</string> <string name="mime_type_generic" msgid="4606589110116560228">"檔案"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> 試算表"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"簡報"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> 簡報"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"啟用飛行模式期間,藍牙會保持開啟"</string> <string name="car_loading_profile" msgid="8219978381196748070">"正在載入"</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> 個檔案</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割螢幕"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 48ff3f66bc4d..2bcae59eb4cf 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"我"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string> @@ -287,8 +291,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"存取你的日曆"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"簡訊"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"傳送及查看簡訊"</string> - <!-- no translation found for permgrouplab_storage (1938416135375282333) --> - <skip /> + <string name="permgrouplab_storage" msgid="1938416135375282333">"檔案和媒體"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"存取裝置中的相片、媒體和檔案"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"麥克風"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"錄音"</string> @@ -314,10 +317,8 @@ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"可使用輕觸、滑動和雙指撥動等手勢。"</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"指紋手勢"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"可以擷取使用者對裝置的指紋感應器執行的手勢。"</string> - <!-- no translation found for capability_title_canTakeScreenshot (3895812893130071930) --> - <skip /> - <!-- no translation found for capability_desc_canTakeScreenshot (7762297374317934052) --> - <skip /> + <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"擷取螢幕畫面"</string> + <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"可以擷取螢幕畫面。"</string> <string name="permlab_statusBar" msgid="8798267849526214017">"停用或變更狀態列"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"允許應用程式停用狀態列,並可新增或移除系統圖示。"</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"以狀態列顯示"</string> @@ -1615,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使你的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙捷徑嗎?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"啟用捷徑功能後,只要同時按下兩個音量鍵 3 秒,就能啟動無障礙功能。\n\n 目前設定的無障礙功能為:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n 如要變更設定的功能,請依序輕觸 [設定] > [無障礙設定]。"</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"空白"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"停用捷徑"</string> @@ -1850,13 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"應用程式目前無法使用"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」。這項設定是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string> <string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作資料夾嗎?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟你的辦公應用程式、通知、資料和其他工作資料夾功能"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string> - <!-- no translation found for app_blocked_title (7353262160455028160) --> - <skip /> - <!-- no translation found for app_blocked_message (542972921087873023) --> - <skip /> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"這個應用程式是專為舊版 Android 所打造,因此可能無法正常運作。請嘗試檢查更新,或是與開發人員聯絡。"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"檢查更新"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"你有新訊息"</string> @@ -1967,14 +1965,10 @@ <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> - <!-- no translation found for battery_saver_off_notification_title (7637255960468032515) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (5544457317418624367) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (4426317048139996888) --> - <skip /> - <!-- no translation found for battery_saver_charged_notification_summary (1031562417867646649) --> - <skip /> + <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> + <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"裝置電力充足,各項功能不再受到限制。"</string> <string name="mime_type_folder" msgid="2203536499348787650">"資料夾"</string> <string name="mime_type_apk" msgid="3168784749499623902">"Android 應用程式"</string> <string name="mime_type_generic" msgid="4606589110116560228">"檔案"</string> @@ -1993,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> 試算表"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"簡報"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> 簡報"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"藍牙將在飛航模式下保持開啟狀態"</string> <string name="car_loading_profile" msgid="8219978381196748070">"載入中"</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> 個檔案</item> @@ -2010,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割畫面模式"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index d7365620da4e..e96696ea0f4a 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -194,6 +194,10 @@ <string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string> + <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) --> + <skip /> + <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) --> + <skip /> <string name="me" msgid="6207584824693813140">"Mina"</string> <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Okukhethwa kukho kwethebhulethi"</string> <string name="power_dialog" product="tv" msgid="7792839006640933763">"Izinketho ze-Android TV"</string> @@ -1612,7 +1616,6 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Uma kuvulwe isinqamuleli, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqala isici sokufinyelela.\n\n Isici samanje sokufinyelela:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Ungashintsha isici kuzilungiselelo > Ukufinyelela."</string> - <string name="accessibility_shortcut_menu_button" msgid="3019329474891857428">"Akunalutho"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Hlela izinqamuleli"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Khansela"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vala isinqamuleli"</string> @@ -1847,11 +1850,11 @@ <string name="app_suspended_title" msgid="888873445010322650">"Uhlelo lokusebenza alutholakali"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> ayitholakali okwamanje. Lokhu kuphethwe i-<xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="app_suspended_more_details" msgid="211260942831587014">"Funda kabanzi"</string> + <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) --> + <skip /> <string name="work_mode_off_title" msgid="5503291976647976560">"Vula iphrofayela yomsebenzi?"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"Izinhlelo zakho zokusebenza zomsebenzi, izaziso, idatha, nezinye izici zephrofayela yomsebenzi kuzovulwa"</string> <string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string> - <string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string> - <string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Lolu hlelo lokusebenza belakhelwe inguqulo endala ye-Android futhi kungenzeka lungasebenzi kahle. Zama ukuhlolela izibuyekezo, noma uxhumane nonjiniyela."</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Hlola izibuyekezo"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Unemilayezo emisha"</string> @@ -1984,6 +1987,7 @@ <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> isipredishithi"</string> <string name="mime_type_presentation" msgid="1145384236788242075">"Iphrezentheshini"</string> <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> iphrezentheshini"</string> + <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"I-Bluetooth izohlala ivuliwe ngesikhathi semodi yendiza"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Iyalayisha"</string> <plurals name="file_count" formatted="false" msgid="7063513834724389247"> <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> amafayela</item> @@ -2001,5 +2005,12 @@ <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Guqula ukuhlukanisa isikrini"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string> + <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) --> + <skip /> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string> + <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> + <!-- no translation found for resolver_personal_tab (2051260504014442073) --> + <skip /> + <!-- no translation found for resolver_work_tab (2690019516263167035) --> + <skip /> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index c9c47b92f782..20901e04e6c5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3714,6 +3714,10 @@ <flag name="flagRequestFingerprintGestures" value="0x00000200" /> <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. --> <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" /> + <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_SERVICE_HANDLES_DOUBLE_TAP}. --> + <flag name="flagServiceHandlesDoubleTap" value="0x00000800" /> + <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. --> + <flag name="flagRequestMultiFingerGestures" value="0x00001000" /> </attr> <!-- Component name of an activity that allows the user to modify the settings for this service. This setting cannot be changed at runtime. --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index be2b678565d3..11cc36544632 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4345,6 +4345,9 @@ <!-- The delete-widget drop target button text --> <string name="kg_reordering_delete_drop_target_text">Remove</string> + <!-- Toast message for background started foreground service while-in-use permission restriction feature --> + <string name="allow_while_in_use_permission_in_fgs">The background started foreground service from <xliff:g id="packageName" example="com.example">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bugreport.</string> + <!-- Message shown in dialog when user is attempting to set the music volume above the recommended maximum level for headphones --> <string name="safe_media_volume_warning" product="default"> @@ -4923,6 +4926,8 @@ </string> <!-- Title of the button to show users more details about why the app has been suspended [CHAR LIMIT=50]--> <string name="app_suspended_more_details">Learn more</string> + <!-- Title of the button to unsuspend a suspended app immediately [CHAR LIMIT=50]--> + <string name="app_suspended_unsuspend_message">Unpause app</string> <!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] --> <string name="work_mode_off_title">Turn on work profile?</string> @@ -4931,13 +4936,6 @@ <!-- Title for button to turn on work profile. [CHAR LIMIT=NONE] --> <string name="work_mode_turn_on">Turn on</string> - <!-- Title of the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=50] --> - <string name="app_blocked_title">App is not available</string> - <!-- Default message shown in the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=NONE] --> - <string name="app_blocked_message"> - <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is not available right now. - </string> - <!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] --> <string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string> <!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] --> @@ -5318,7 +5316,8 @@ <string name="accessibility_system_action_lock_screen_label">Lock Screen</string> <!-- Label for taking screenshot action [CHAR LIMIT=NONE] --> <string name="accessibility_system_action_screenshot_label">Screenshot</string> - + <!-- Label for showing accessibility menu action [CHAR LIMIT=NONE] --> + <string name="accessibility_system_action_accessibility_menu_label">Accessibility Menu</string> <!-- Accessibility description of caption view --> <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 18ca003dd8c6..d2384859531c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3039,11 +3039,9 @@ <java-symbol type="string" name="app_suspended_title" /> <java-symbol type="string" name="app_suspended_more_details" /> + <java-symbol type="string" name="app_suspended_unsuspend_message" /> <java-symbol type="string" name="app_suspended_default_message" /> - <java-symbol type="string" name="app_blocked_title" /> - <java-symbol type="string" name="app_blocked_message" /> - <!-- Used internally for assistant to launch activity transitions --> <java-symbol type="id" name="cross_task_transition" /> @@ -3804,6 +3802,7 @@ <java-symbol type="string" name="accessibility_system_action_recents_label" /> <java-symbol type="string" name="accessibility_system_action_screenshot_label" /> <java-symbol type="string" name="accessibility_system_action_toggle_split_screen_label" /> + <java-symbol type="string" name="accessibility_system_action_accessibility_menu_label" /> <java-symbol type="string" name="accessibility_freeform_caption" /> @@ -3848,4 +3847,6 @@ <java-symbol type="string" name="resolver_work_tab" /> <java-symbol type="id" name="stub" /> + <!-- Toast message for background started foreground service while-in-use permission restriction feature --> + <java-symbol type="string" name="allow_while_in_use_permission_in_fgs" /> </resources> diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index d8b527c8a11a..c986db8b2a83 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -96,16 +96,6 @@ public class ActivityThreadTest { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } - @Test - public void testSleepAndStop() throws Exception { - final Activity activity = mActivityTestRule.launchActivity(new Intent()); - final IApplicationThread appThread = activity.getActivityThread().getApplicationThread(); - - appThread.scheduleSleeping(activity.getActivityToken(), true /* sleeping */); - appThread.scheduleTransaction(newStopTransaction(activity)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - /** Verify that repeated resume requests to activity will be ignored. */ @Test public void testRepeatedResume() throws Exception { diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java index abba7fcce6c7..4a4f13676cb3 100644 --- a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java +++ b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java @@ -20,12 +20,11 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; -import android.app.appsearch.AppSearch.Document; - import androidx.test.filters.SmallTest; import com.google.android.icing.proto.DocumentProto; import com.google.android.icing.proto.PropertyProto; +import com.google.android.icing.protobuf.ByteString; import org.junit.Test; @@ -36,22 +35,36 @@ import java.util.List; @SmallTest public class AppSearchDocumentTest { + private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3}; + private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6}; + private static final AppSearchDocument sDocumentProperties1 = new AppSearchDocument + .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1") + .build(); + private static final AppSearchDocument sDocumentProperties2 = new AppSearchDocument + .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2") + .build(); @Test public void testDocumentEquals_Identical() { - Document document1 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) + .setTtlMillis(1L) .setProperty("longKey1", 1L, 2L, 3L) .setProperty("doubleKey1", 1.0, 2.0, 3.0) .setProperty("booleanKey1", true, false, true) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setProperty("byteKey1", sByteArray1, sByteArray2) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); - Document document2 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) + .setTtlMillis(1L) .setProperty("longKey1", 1L, 2L, 3L) .setProperty("doubleKey1", 1.0, 2.0, 3.0) .setProperty("booleanKey1", true, false, true) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setProperty("byteKey1", sByteArray1, sByteArray2) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(document1).isEqualTo(document2); assertThat(document1.hashCode()).isEqualTo(document2.hashCode()); @@ -59,20 +72,24 @@ public class AppSearchDocumentTest { @Test public void testDocumentEquals_DifferentOrder() { - Document document1 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("longKey1", 1L, 2L, 3L) + .setProperty("byteKey1", sByteArray1, sByteArray2) .setProperty("doubleKey1", 1.0, 2.0, 3.0) .setProperty("booleanKey1", true, false, true) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") .build(); // Create second document with same parameter but different order. - Document document2 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("booleanKey1", true, false, true) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") .setProperty("doubleKey1", 1.0, 2.0, 3.0) + .setProperty("byteKey1", sByteArray1, sByteArray2) .setProperty("longKey1", 1L, 2L, 3L) .build(); assertThat(document1).isEqualTo(document2); @@ -81,13 +98,13 @@ public class AppSearchDocumentTest { @Test public void testDocumentEquals_Failure() { - Document document1 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("longKey1", 1L, 2L, 3L) .build(); // Create second document with same order but different value. - Document document2 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("longKey1", 1L, 2L, 4L) // Different .build(); @@ -97,13 +114,13 @@ public class AppSearchDocumentTest { @Test public void testDocumentEquals_Failure_RepeatedFieldOrder() { - Document document1 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("booleanKey1", true, false, true) .build(); // Create second document with same order but different value. - Document document2 = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("booleanKey1", true, true, false) // Different .build(); @@ -113,14 +130,19 @@ public class AppSearchDocumentTest { @Test public void testDocumentGetSingleValue() { - Document document = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setScore(1) + .setTtlMillis(1L) .setProperty("longKey1", 1L) .setProperty("doubleKey1", 1.0) .setProperty("booleanKey1", true) - .setProperty("stringKey1", "test-value1").build(); + .setProperty("stringKey1", "test-value1") + .setProperty("byteKey1", sByteArray1) + .setProperty("documentKey1", sDocumentProperties1) + .build(); assertThat(document.getUri()).isEqualTo("uri1"); + assertThat(document.getTtlMillis()).isEqualTo(1L); assertThat(document.getSchemaType()).isEqualTo("schemaType1"); assertThat(document.getCreationTimestampMillis()).isEqualTo(5); assertThat(document.getScore()).isEqualTo(1); @@ -128,16 +150,21 @@ public class AppSearchDocumentTest { assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0); assertThat(document.getPropertyBoolean("booleanKey1")).isTrue(); assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1"); + assertThat(document.getPropertyBytes("byteKey1")) + .asList().containsExactly((byte) 1, (byte) 2, (byte) 3); + assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1); } @Test public void testDocumentGetArrayValues() { - Document document = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setProperty("longKey1", 1L, 2L, 3L) .setProperty("doubleKey1", 1.0, 2.0, 3.0) .setProperty("booleanKey1", true, false, true) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setProperty("byteKey1", sByteArray1, sByteArray2) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(document.getUri()).isEqualTo("uri1"); @@ -149,11 +176,15 @@ public class AppSearchDocumentTest { .containsExactly(true, false, true); assertThat(document.getPropertyStringArray("stringKey1")).asList() .containsExactly("test-value1", "test-value2", "test-value3"); + assertThat(document.getPropertyBytesArray("byteKey1")).asList() + .containsExactly(sByteArray1, sByteArray2); + assertThat(document.getPropertyDocumentArray("documentKey1")).asList() + .containsExactly(sDocumentProperties1, sDocumentProperties2); } @Test public void testDocumentGetValues_DifferentTypes() { - Document document = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") .setScore(1) .setProperty("longKey1", 1L) .setProperty("booleanKey1", true, false, true) @@ -180,25 +211,32 @@ public class AppSearchDocumentTest { @Test public void testDocumentInvalid() { - Document.Builder builder = Document.newBuilder("uri1", "schemaType1"); + AppSearchDocument.Builder builder = new AppSearchDocument.Builder("uri1", "schemaType1"); assertThrows( IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{})); } @Test public void testDocumentProtoPopulation() { - Document document = Document.newBuilder("uri1", "schemaType1") + AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") .setCreationTimestampMillis(5L) .setScore(1) + .setTtlMillis(1L) .setProperty("longKey1", 1L) .setProperty("doubleKey1", 1.0) .setProperty("booleanKey1", true) .setProperty("stringKey1", "test-value1") + .setProperty("byteKey1", sByteArray1) + .setProperty("documentKey1", sDocumentProperties1) .build(); // Create the Document proto. Need to sort the property order by key. DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder() - .setUri("uri1").setSchema("schemaType1").setScore(1).setCreationTimestampMs(5L); + .setUri("uri1") + .setSchema("schemaType1") + .setCreationTimestampMs(5L) + .setScore(1) + .setTtlMs(1L); HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>(); propertyProtoMap.put("longKey1", PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L)); @@ -208,6 +246,12 @@ public class AppSearchDocumentTest { PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true)); propertyProtoMap.put("stringKey1", PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1")); + propertyProtoMap.put("byteKey1", + PropertyProto.newBuilder().setName("byteKey1").addBytesValues( + ByteString.copyFrom(sByteArray1))); + propertyProtoMap.put("documentKey1", + PropertyProto.newBuilder().setName("documentKey1") + .addDocumentValues(sDocumentProperties1.getProto())); List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet()); Collections.sort(sortedKey); for (String key : sortedKey) { diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java index c50b1da71d02..6aa16cc1e323 100644 --- a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java +++ b/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java @@ -18,8 +18,6 @@ package android.app.appsearch; import static com.google.common.truth.Truth.assertThat; -import android.app.appsearch.AppSearch.Email; - import androidx.test.filters.SmallTest; import org.junit.Test; @@ -29,7 +27,7 @@ public class AppSearchEmailTest { @Test public void testBuildEmailAndGetValue() { - Email email = Email.newBuilder("uri") + AppSearchEmail email = new AppSearchEmail.Builder("uri") .setFrom("FakeFromAddress") .setCc("CC1", "CC2") // Score and Property are mixed into the middle to make sure DocumentBuilder's diff --git a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java index c5986bb2f07b..b29483c2e3b3 100644 --- a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java +++ b/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java @@ -19,28 +19,42 @@ package android.app.appsearch.impl; import static com.google.common.truth.Truth.assertThat; import android.annotation.NonNull; -import android.app.appsearch.AppSearch.Document; +import android.app.appsearch.AppSearchDocument; import androidx.test.filters.SmallTest; import org.junit.Test; -/** Tests that {@link Document} and {@link Document.Builder} are extendable by developers. +/** + * Tests that {@link AppSearchDocument} and {@link AppSearchDocument.Builder} are extendable by + * developers. * - * <p>This class is intentionally in a different package than {@link Document} to make sure there - * are no package-private methods required for external developers to add custom types. + * <p>This class is intentionally in a different package than {@link AppSearchDocument} to make sure + * there are no package-private methods required for external developers to add custom types. */ @SmallTest public class CustomerDocumentTest { + + private static byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3}; + private static byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6}; + private static AppSearchDocument sDocumentProperties1 = new AppSearchDocument + .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1") + .build(); + private static AppSearchDocument sDocumentProperties2 = new AppSearchDocument + .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2") + .build(); + @Test public void testBuildCustomerDocument() { - CustomerDocument customerDocument = CustomerDocument.newBuilder("uri1") + CustomerDocument customerDocument = new CustomerDocument.Builder("uri1") .setScore(1) .setCreationTimestampMillis(0) .setProperty("longKey1", 1L, 2L, 3L) .setProperty("doubleKey1", 1.0, 2.0, 3.0) .setProperty("booleanKey1", true, false, true) .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") + .setProperty("byteKey1", sByteArray1, sByteArray2) + .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) .build(); assertThat(customerDocument.getUri()).isEqualTo("uri1"); @@ -55,22 +69,22 @@ public class CustomerDocumentTest { .containsExactly(true, false, true); assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList() .containsExactly("test-value1", "test-value2", "test-value3"); + assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList() + .containsExactly(sByteArray1, sByteArray2); + assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList() + .containsExactly(sDocumentProperties1, sDocumentProperties2); } /** * An example document type for test purposes, defined outside of * {@link android.app.appsearch.AppSearch} (the way an external developer would define it). */ - private static class CustomerDocument extends Document { - private CustomerDocument(Document document) { + private static class CustomerDocument extends AppSearchDocument { + private CustomerDocument(AppSearchDocument document) { super(document); } - public static CustomerDocument.Builder newBuilder(String uri) { - return new CustomerDocument.Builder(uri); - } - - public static class Builder extends Document.Builder<CustomerDocument.Builder> { + public static class Builder extends AppSearchDocument.Builder<CustomerDocument.Builder> { private Builder(@NonNull String uri) { super(uri, "customerDocument"); } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index ecea9011e704..372b8c294702 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -448,10 +448,6 @@ public class TransactionParcelTests { } @Override - public void scheduleSleeping(IBinder iBinder, boolean b) throws RemoteException { - } - - @Override public void profilerControl(boolean b, ProfilerInfo profilerInfo, int i) throws RemoteException { } diff --git a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java index e48f1c3a89c7..c0d9be5dde59 100644 --- a/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java @@ -18,12 +18,9 @@ package android.content.integrity; import static android.content.integrity.TestUtils.assertExpectException; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AtomicFormula.BooleanAtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.os.Parcel; @@ -36,19 +33,93 @@ public class AtomicFormulaTest { @Test public void testValidAtomicFormula_stringValue() { + String packageName = "com.test.app"; StringAtomicFormula stringAtomicFormula = new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); + AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */false); - assertEquals(AtomicFormula.PACKAGE_NAME, stringAtomicFormula.getKey()); + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); } @Test - public void testValidAtomicFormula_intValue() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); + public void testValidAtomicFormula_stringValue_autoHash_packageNameLessThanLimit() { + String packageName = "com.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, packageName); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_longPackageName() { + String packageName = "com.test.app.test.app.test.app.test.app.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, packageName); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_installerNameLessThanLimit() { + String installerName = "com.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME, installerName); + + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isFalse(); + } + + @Test + public void testValidAtomicFormula_stringValue_autoHash_longInstallerName() { + String installerName = "com.test.app.test.app.test.app.test.app.test.app"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_NAME, installerName); - assertEquals(AtomicFormula.VERSION_CODE, intAtomicFormula.getKey()); + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_appCertificateAutoHashed() { + String appCert = "cert"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, appCert); + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCert); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_stringValue_installerCertificateAutoHashed() { + String installerCert = "cert"; + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE, + installerCert); + + assertThat(stringAtomicFormula.getKey()).isEqualTo( + AtomicFormula.INSTALLER_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCert); + assertThat(stringAtomicFormula.getIsHashedValue()).isTrue(); + } + + @Test + public void testValidAtomicFormula_longValue() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + + assertThat(longAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(longAtomicFormula.getValue()).isEqualTo(1); } @Test @@ -56,7 +127,8 @@ public class AtomicFormulaTest { BooleanAtomicFormula atomicFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); - assertEquals(AtomicFormula.PRE_INSTALLED, atomicFormula.getKey()); + assertThat(atomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); + assertThat(atomicFormula.getValue()).isTrue(); } @Test @@ -73,12 +145,14 @@ public class AtomicFormulaTest { } @Test - public void testInvalidAtomicFormula_intValue() { + public void testInvalidAtomicFormula_longValue() { assertExpectException( IllegalArgumentException.class, /* expectedExceptionMessageRegex */ - String.format("Key PACKAGE_NAME cannot be used with IntAtomicFormula"), - () -> new IntAtomicFormula(AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1)); + String.format("Key PACKAGE_NAME cannot be used with LongAtomicFormula"), + () -> + new AtomicFormula.LongAtomicFormula( + AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1)); } @Test @@ -91,197 +165,174 @@ public class AtomicFormulaTest { } @Test - public void testIsSatisfiable_string_true() { - StringAtomicFormula stringAtomicFormula = + public void testParcelUnparcel_string() { + StringAtomicFormula formula = new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("com.test.app").build(); + AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p); - assertTrue(stringAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_string_false() { - StringAtomicFormula stringAtomicFormula = - new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build(); + public void testParcelUnparcel_int() { + AtomicFormula.LongAtomicFormula formula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + AtomicFormula.LongAtomicFormula newFormula = + AtomicFormula.LongAtomicFormula.CREATOR.createFromParcel(p); - assertFalse(stringAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_int_eq_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + public void testParcelUnparcel_bool() { + BooleanAtomicFormula formula = new BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(newFormula).isEqualTo(formula); } @Test - public void testIsSatisfiable_int_eq_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); - - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + public void testInvalidAtomicFormula_invalidKey() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown key: -1", + () -> new AtomicFormula.LongAtomicFormula(/* key= */ -1, AtomicFormula.EQ, 0)); } @Test - public void testIsSatisfiable_int_gt_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 0); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); - - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + public void testInvalidAtomicFormula_invalidOperator() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown operator: -1", + () -> + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, /* operator= */ -1, 0)); } @Test - public void testIsSatisfiable_int_gt_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1); + public void testFormulaMatches_string_true() { + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ + false); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + getAppInstallMetadataBuilder().setPackageName("com.test.app").build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(stringAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_ge_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 0); + public void testFormulaMatches_string_false() { + StringAtomicFormula stringAtomicFormula = + new StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ + false); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(1).build(); + getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(stringAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_ge_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 1); + public void testFormulaMatches_long_eq_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setVersionCode(0).build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_lt_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); + public void testFormulaMatches_long_eq_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(0).build(); + getAppInstallMetadataBuilder().setVersionCode(1).build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_lt_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); + public void testFormulaMatches_long_gt_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, + 0); AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setVersionCode(2).build(); + getAppInstallMetadataBuilder().setVersionCode(1).build(); - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_int_le_true() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); + public void testFormulaMatches_long_gt_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, + 1); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setVersionCode(0).build(); - assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata)); + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_int_le_false() { - IntAtomicFormula intAtomicFormula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1); - AppInstallMetadata appInstallMetadata = + public void testFormulaMatches_long_gte_true() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder().setVersionCode(1).build(); + assertThat(longAtomicFormula.matches(appInstallMetadata1)).isTrue(); + + AppInstallMetadata appInstallMetadata2 = getAppInstallMetadataBuilder().setVersionCode(2).build(); + assertThat(longAtomicFormula.matches(appInstallMetadata2)).isTrue(); + } - assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata)); + @Test + public void testFormulaMatches_long_gte_false() { + AtomicFormula.LongAtomicFormula longAtomicFormula = + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.GTE, 1); + AppInstallMetadata appInstallMetadata = + getAppInstallMetadataBuilder().setVersionCode(0).build(); + + assertThat(longAtomicFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_bool_true() { + public void testFormulaMatches_bool_true() { BooleanAtomicFormula boolFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setIsPreInstalled(true).build(); - assertTrue(boolFormula.isSatisfied(appInstallMetadata)); + assertThat(boolFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_bool_false() { + public void testFormulaMatches_bool_false() { BooleanAtomicFormula boolFormula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setIsPreInstalled(false).build(); - assertFalse(boolFormula.isSatisfied(appInstallMetadata)); - } - - @Test - public void testParcelUnparcel_string() { - StringAtomicFormula formula = - new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testParcelUnparcel_int() { - IntAtomicFormula formula = - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - IntAtomicFormula newFormula = IntAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testParcelUnparcel_bool() { - BooleanAtomicFormula formula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p); - - assertEquals(formula, newFormula); - } - - @Test - public void testInvalidAtomicFormula_invalidKey() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown key: -1", - () -> new IntAtomicFormula(/* key= */ -1, AtomicFormula.EQ, 0)); - } - - @Test - public void testInvalidAtomicFormula_invalidOperator() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown operator: -1", - () -> new IntAtomicFormula(AtomicFormula.VERSION_CODE, /* operator= */ -1, 0)); + assertThat(boolFormula.matches(appInstallMetadata)).isFalse(); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java index 927e4dbb5200..fa3d671c09e5 100644 --- a/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java +++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java @@ -18,9 +18,9 @@ package android.content.integrity; import static android.content.integrity.TestUtils.assertExpectException; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import android.os.Parcel; @@ -38,7 +38,7 @@ public class CompoundFormulaTest { new AtomicFormula.StringAtomicFormula( AtomicFormula.PACKAGE_NAME, "test1", /* isHashedValue= */ false); private static final AtomicFormula ATOMIC_FORMULA_2 = - new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1); + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1); @Test public void testValidCompoundFormula() { @@ -75,163 +75,156 @@ public class CompoundFormulaTest { } @Test - public void testIsSatisfiable_notFalse_true() { - CompoundFormula compoundFormula = - new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); - AppInstallMetadata appInstallMetadata = - getAppInstallMetadataBuilder().setPackageName("test2").build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); + public void testParcelUnparcel() { + CompoundFormula formula = + new CompoundFormula( + CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1)); + Parcel p = Parcel.obtain(); + formula.writeToParcel(p, 0); + p.setDataPosition(0); + CompoundFormula newFormula = CompoundFormula.CREATOR.createFromParcel(p); + + assertEquals(formula, newFormula); + } - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + @Test + public void testInvalidCompoundFormula_invalidConnector() { + assertExpectException( + IllegalArgumentException.class, + /* expectedExceptionMessageRegex */ "Unknown connector: -1", + () -> + new CompoundFormula( + /* connector= */ -1, + Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2))); } @Test - public void testIsSatisfiable_notTrue_false() { + public void testFormulaMatches_notFalse_true() { + AppInstallMetadata appInstallMetadata = + getAppInstallMetadataBuilder().setPackageName("test2").build(); + + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + CompoundFormula compoundFormula = new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); + } + + @Test + public void testFormulaMatches_notTrue_false() { AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + + CompoundFormula compoundFormula = + new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1)); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_trueAndTrue_true() { + public void testFormulaMatches_trueAndTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build(); // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_trueAndFalse_false() { + public void testFormulaMatches_trueAndFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_falseAndTrue_false() { + public void testFormulaMatches_falseAndTrue_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_falseAndFalse_false() { + public void testFormulaMatches_falseAndFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } @Test - public void testIsSatisfiable_trueOrTrue_true() { + public void testFormulaMatches_trueOrTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_trueOrFalse_true() { + public void testFormulaMatches_trueOrFalse_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build(); - // validate assumptions about the metadata - assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isTrue(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_falseOrTrue_true() { + public void testFormulaMatches_falseOrTrue_true() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - assertTrue(compoundFormula.isSatisfied(appInstallMetadata)); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isTrue(); + assertThat(compoundFormula.matches(appInstallMetadata)).isTrue(); } @Test - public void testIsSatisfiable_falseOrFalse_false() { + public void testFormulaMatches_falseOrFalse_false() { CompoundFormula compoundFormula = new CompoundFormula( CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)); AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build(); - // validate assumptions about the metadata - assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata)); - assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata)); - - assertFalse(compoundFormula.isSatisfied(appInstallMetadata)); - } - - @Test - public void testParcelUnparcel() { - CompoundFormula formula = - new CompoundFormula( - CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1)); - Parcel p = Parcel.obtain(); - formula.writeToParcel(p, 0); - p.setDataPosition(0); - CompoundFormula newFormula = CompoundFormula.CREATOR.createFromParcel(p); - assertEquals(formula, newFormula); - } - - @Test - public void testInvalidCompoundFormula_invalidConnector() { - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex */ "Unknown connector: -1", - () -> - new CompoundFormula( - /* connector= */ -1, - Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2))); + assertThat(ATOMIC_FORMULA_1.matches(appInstallMetadata)).isFalse(); + assertThat(ATOMIC_FORMULA_2.matches(appInstallMetadata)).isFalse(); + assertThat(compoundFormula.matches(appInstallMetadata)).isFalse(); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java new file mode 100644 index 000000000000..c1806028f75b --- /dev/null +++ b/core/tests/coretests/src/android/content/integrity/IntegrityFormulaTest.java @@ -0,0 +1,214 @@ +/* + * 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 android.content.integrity; + +import static android.content.integrity.IntegrityFormula.COMPOUND_FORMULA_TAG; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class IntegrityFormulaTest { + + @Test + public void createEqualsFormula_packageName() { + String packageName = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PACKAGE_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(packageName); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false); + } + + @Test + public void createEqualsFormula_appCertificate() { + String appCertificate = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.APP_CERTIFICATE.equalTo(appCertificate); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.APP_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(appCertificate); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true); + } + + @Test + public void createEqualsFormula_installerName() { + String installerName = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.INSTALLER_NAME.equalTo(installerName); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_NAME); + assertThat(stringAtomicFormula.getValue()).isEqualTo(installerName); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(false); + } + + @Test + public void createEqualsFormula_installerCertificate() { + String installerCertificate = "com.test.app"; + IntegrityFormula formula = + IntegrityFormula.INSTALLER_CERTIFICATE.equalTo(installerCertificate); + + AtomicFormula.StringAtomicFormula stringAtomicFormula = + (AtomicFormula.StringAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.INSTALLER_CERTIFICATE); + assertThat(stringAtomicFormula.getValue()).doesNotMatch(installerCertificate); + assertThat(stringAtomicFormula.getIsHashedValue()).isEqualTo(true); + } + + @Test + public void createEqualsFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.equalTo(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.EQ); + } + + @Test + public void createEqualsFormula_invalidKeyTypeForStringParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PRE_INSTALLED.equalTo("wrongString")); + } + + @Test + public void createEqualsFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.equalTo(12)); + } + + @Test + public void createGreaterThanFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.greaterThan(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GT); + } + + @Test + public void createGreaterThanFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.greaterThan(12)); + } + + @Test + public void createGreaterThanOrEqualsToFormula_versionCode() { + int versionCode = 12; + IntegrityFormula formula = + IntegrityFormula.VERSION_CODE.greaterThanOrEquals(versionCode); + + AtomicFormula.LongAtomicFormula stringAtomicFormula = + (AtomicFormula.LongAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.VERSION_CODE); + assertThat(stringAtomicFormula.getValue()).isEqualTo(versionCode); + assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GTE); + } + + @Test + public void createGreaterThanOrEqualsToFormula_invalidKeyTypeForLongParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.greaterThanOrEquals(12)); + } + + @Test + public void createIsTrueFormula_preInstalled() { + IntegrityFormula formula = IntegrityFormula.PRE_INSTALLED.equalTo(true); + + AtomicFormula.BooleanAtomicFormula stringAtomicFormula = + (AtomicFormula.BooleanAtomicFormula) formula; + + assertThat(stringAtomicFormula.getKey()).isEqualTo(AtomicFormula.PRE_INSTALLED); + assertThat(stringAtomicFormula.getValue()).isTrue(); + } + + @Test + public void createIsTrueFormula_invalidKeyTypeForBoolParameter() { + assertThrows( + IllegalArgumentException.class, + () -> IntegrityFormula.PACKAGE_NAME.equalTo(true)); + } + + @Test + public void createAllFormula() { + String packageName = "com.test.package"; + String certificateName = "certificate"; + IntegrityFormula formula1 = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + IntegrityFormula formula2 = + IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName); + + IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } + + @Test + public void createAnyFormula() { + String packageName = "com.test.package"; + String certificateName = "certificate"; + IntegrityFormula formula1 = + IntegrityFormula.PACKAGE_NAME.equalTo(packageName); + IntegrityFormula formula2 = + IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName); + + IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } + + @Test + public void createNotFormula() { + String packageName = "com.test.package"; + + IntegrityFormula compoundFormula = + IntegrityFormula.not( + IntegrityFormula.PACKAGE_NAME.equalTo(packageName)); + + assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG); + } +} diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java b/core/tests/coretests/src/android/content/integrity/IntegrityUtilsTest.java index ac7f8f98ab9b..639adf6a05d7 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityUtilsTest.java +++ b/core/tests/coretests/src/android/content/integrity/IntegrityUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,48 +14,44 @@ * limitations under the License. */ -package com.android.server.integrity; +package android.content.integrity; -import static com.android.server.integrity.IntegrityUtils.getBytesFromHexDigest; -import static com.android.server.integrity.IntegrityUtils.getHexDigest; -import static com.android.server.testutils.TestUtils.assertExpectException; +import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -import androidx.test.runner.AndroidJUnit4; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; -/** Unit test for {@link com.android.server.integrity.IntegrityUtils} */ -@RunWith(AndroidJUnit4.class) +/** Unit test for {@link IntegrityUtils} */ +@RunWith(JUnit4.class) public class IntegrityUtilsTest { private static final String HEX_DIGEST = "1234567890ABCDEF"; private static final byte[] BYTES = - new byte[] {0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF}; + new byte[]{0x12, 0x34, 0x56, 0x78, (byte) 0x90, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF}; @Test public void testGetBytesFromHexDigest() { - assertArrayEquals(BYTES, getBytesFromHexDigest(HEX_DIGEST)); + assertArrayEquals(BYTES, IntegrityUtils.getBytesFromHexDigest(HEX_DIGEST)); } @Test public void testGetHexDigest() { - assertEquals(HEX_DIGEST, getHexDigest(BYTES)); + assertThat(IntegrityUtils.getHexDigest(BYTES)).isEqualTo(HEX_DIGEST); } @Test public void testInvalidHexDigest() { - assertExpectException( + TestUtils.assertExpectException( IllegalArgumentException.class, "must have even length", - () -> getBytesFromHexDigest("ABC")); + () -> IntegrityUtils.getBytesFromHexDigest("ABC")); - assertExpectException( + TestUtils.assertExpectException( IllegalArgumentException.class, "Invalid hex char", - () -> getBytesFromHexDigest("GH")); + () -> IntegrityUtils.getBytesFromHexDigest("GH")); } } diff --git a/core/tests/coretests/src/android/content/integrity/RuleTest.java b/core/tests/coretests/src/android/content/integrity/RuleTest.java index 19e74e6b93cc..8c4cfca39e90 100644 --- a/core/tests/coretests/src/android/content/integrity/RuleTest.java +++ b/core/tests/coretests/src/android/content/integrity/RuleTest.java @@ -35,11 +35,15 @@ public class RuleTest { private static final @Rule.Effect int DENY_EFFECT = Rule.DENY; private static final String PACKAGE_NAME = "com.test.app"; private static final String APP_CERTIFICATE = "test_cert"; - private static final Formula PACKAGE_NAME_ATOMIC_FORMULA = - new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME, + private static final IntegrityFormula PACKAGE_NAME_ATOMIC_FORMULA = + new AtomicFormula.StringAtomicFormula( + AtomicFormula.PACKAGE_NAME, + PACKAGE_NAME, /* isHashedValue= */ false); - private static final Formula APP_CERTIFICATE_ATOMIC_FORMULA = - new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE, + private static final IntegrityFormula APP_CERTIFICATE_ATOMIC_FORMULA = + new AtomicFormula.StringAtomicFormula( + AtomicFormula.APP_CERTIFICATE, + APP_CERTIFICATE, /* isHashedValue= */ false); @Test diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java index 895b22c7037c..4370462279b2 100644 --- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java +++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java @@ -132,7 +132,7 @@ public class BrightnessConfigurationTest { BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); builder.setShouldCollectColorSamples(true); - builder.setShortTermModelTimeout(1234L); + builder.setShortTermModelTimeoutMillis(1234L); builder.setShortTermModelLowerLuxMultiplier(0.9f); builder.setShortTermModelUpperLuxMultiplier(0.2f); builder.addCorrectionByCategory(3, @@ -153,7 +153,7 @@ public class BrightnessConfigurationTest { BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); builder.setShouldCollectColorSamples(true); - builder.setShortTermModelTimeout(123L); + builder.setShortTermModelTimeoutMillis(123L); builder.setShortTermModelLowerLuxMultiplier(0.4f); builder.setShortTermModelUpperLuxMultiplier(0.8f); builder.addCorrectionByCategory(3, @@ -236,7 +236,7 @@ public class BrightnessConfigurationTest { assertNotEquals(baseConfig, colorCollectionDiffers); builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); - builder.setShortTermModelTimeout(300L); + builder.setShortTermModelTimeoutMillis(300L); BrightnessConfiguration timeoutDiffers = builder.build(); assertNotEquals(baseConfig, timeoutDiffers); diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 411868d8befe..d4c362143bf0 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -92,7 +92,9 @@ import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Function; /** @@ -976,6 +978,8 @@ public class ChooserActivityTest { .launchActivity(Intent.createChooser(sendIntent, null)); // Insert the direct share target + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); + directShareToShortcutInfos.put(serviceTargets.get(0), null); InstrumentationRegistry.getInstrumentation().runOnMainSync( () -> activity.getAdapter().addServiceResults( activity.createTestDisplayResolveInfo(sendIntent, @@ -985,7 +989,8 @@ public class ChooserActivityTest { sendIntent, /* resolveInfoPresentationGetter */ null), serviceTargets, - TARGET_TYPE_CHOOSER_TARGET) + TARGET_TYPE_CHOOSER_TARGET, + directShareToShortcutInfos) ); // Thread.sleep shouldn't be a thing in an integration test but it's @@ -1044,6 +1049,8 @@ public class ChooserActivityTest { .launchActivity(Intent.createChooser(sendIntent, null)); // Insert the direct share target + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); + directShareToShortcutInfos.put(serviceTargets.get(0), null); InstrumentationRegistry.getInstrumentation().runOnMainSync( () -> activity.getAdapter().addServiceResults( activity.createTestDisplayResolveInfo(sendIntent, @@ -1053,7 +1060,8 @@ public class ChooserActivityTest { sendIntent, /* resolveInfoPresentationGetter */ null), serviceTargets, - TARGET_TYPE_CHOOSER_TARGET) + TARGET_TYPE_CHOOSER_TARGET, + directShareToShortcutInfos) ); // Thread.sleep shouldn't be a thing in an integration test but it's // necessary here because of the way the code is structured @@ -1128,6 +1136,8 @@ public class ChooserActivityTest { final ChooserWrapperActivity activity = mActivityRule .launchActivity(Intent.createChooser(sendIntent, null)); // Insert the direct share target + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); + directShareToShortcutInfos.put(serviceTargets.get(0), null); InstrumentationRegistry.getInstrumentation().runOnMainSync( () -> activity.getAdapter().addServiceResults( activity.createTestDisplayResolveInfo(sendIntent, @@ -1137,7 +1147,8 @@ public class ChooserActivityTest { sendIntent, /* resolveInfoPresentationGetter */ null), serviceTargets, - TARGET_TYPE_CHOOSER_TARGET) + TARGET_TYPE_CHOOSER_TARGET, + directShareToShortcutInfos) ); // Thread.sleep shouldn't be a thing in an integration test but it's // necessary here because of the way the code is structured diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 4febf0c084c0..133b1aed68f1 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -361,6 +361,8 @@ applications that come with the platform <!-- Permissions required to test ambient display. --> <permission name="android.permission.READ_DREAM_STATE" /> <permission name="android.permission.WRITE_DREAM_STATE" /> + <!-- Permission required to test lights control APIs. --> + <permission name="android.permission.CONTROL_DEVICE_LIGHTS" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 1e98e3afa97c..79589bf13853 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -697,12 +697,6 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-650040763": { - "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, "-635082269": { "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", "level": "INFO", @@ -901,6 +895,12 @@ "group": "WM_DEBUG_WINDOW_MOVEMENT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-177040661": { + "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, "-167822951": { "message": "Attempted to add starting window to token with already existing starting window", "level": "WARN", @@ -1105,6 +1105,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, + "202263690": { + "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, "221540118": { "message": "mUserActivityTimeout set to %d", "level": "DEBUG", diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index ac094ba5d5d2..9c2e95fab455 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -2132,7 +2132,7 @@ public final class Bitmap implements Parcelable { public void writeToParcel(Parcel p, int flags) { checkRecycled("Can't parcel a recycled bitmap"); noteHardwareBitmapSlowCall(); - if (!nativeWriteToParcel(mNativePtr, isMutable(), mDensity, p)) { + if (!nativeWriteToParcel(mNativePtr, mDensity, p)) { throw new RuntimeException("native writeToParcel failed"); } } @@ -2285,7 +2285,6 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCreateFromParcel(Parcel p); // returns true on success private static native boolean nativeWriteToParcel(long nativeBitmap, - boolean isMutable, int density, Parcel p); // returns a new bitmap built from the native bitmap's alpha, and the paint diff --git a/libs/services/Android.bp b/libs/services/Android.bp index 901ffaa59cd1..9b047ca22d19 100644 --- a/libs/services/Android.bp +++ b/libs/services/Android.bp @@ -21,7 +21,6 @@ cc_library_shared { "src/content/ComponentName.cpp", "src/os/DropBoxManager.cpp", "src/os/StatsDimensionsValue.cpp", - "src/os/StatsLogEventWrapper.cpp", ], shared_libs: [ diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h deleted file mode 100644 index 8de2ab49f42b..000000000000 --- a/libs/services/include/android/os/StatsLogEventWrapper.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef STATS_LOG_EVENT_WRAPPER_H -#define STATS_LOG_EVENT_WRAPPER_H - -#include <binder/Parcel.h> -#include <binder/Parcelable.h> -#include <binder/Status.h> -#include <utils/RefBase.h> -#include <vector> - -namespace android { -namespace os { - -/** - * A wrapper for a union type to contain multiple types of values. - * - */ -struct StatsLogValue { - // Keep in sync with FieldValue.h - enum STATS_LOG_VALUE_TYPE { - UNKNOWN = 0, - INT = 1, - LONG = 2, - FLOAT = 3, - DOUBLE = 4, - STRING = 5, - STORAGE = 6 - }; - - StatsLogValue() : type(UNKNOWN) {} - - StatsLogValue(int32_t v) { - int_value = v; - type = INT; - } - - StatsLogValue(int64_t v) { - long_value = v; - type = LONG; - } - - StatsLogValue(float v) { - float_value = v; - type = FLOAT; - } - - StatsLogValue(double v) { - double_value = v; - type = DOUBLE; - } - - StatsLogValue(const std::string& v) { - str_value = v; - type = STRING; - } - - void setType(STATS_LOG_VALUE_TYPE t) { type = t; } - - union { - int32_t int_value; - int64_t long_value; - float float_value; - double double_value; - }; - std::string str_value; - std::vector<uint8_t> storage_value; - - STATS_LOG_VALUE_TYPE type; -}; - -struct WorkChain { - std::vector<int32_t> uids; - std::vector<std::string> tags; -}; - -// Represents a parcelable object. Only used to send data from Android OS to statsd. -class StatsLogEventWrapper : public android::Parcelable { - public: - StatsLogEventWrapper(); - - StatsLogEventWrapper(StatsLogEventWrapper&& in) = default; - - android::status_t writeToParcel(android::Parcel* out) const; - - android::status_t readFromParcel(const android::Parcel* in); - - int getTagId() const { return mTagId; } - - int64_t getElapsedRealTimeNs() const { return mElapsedRealTimeNs; } - - int64_t getWallClockTimeNs() const { return mWallClockTimeNs; } - - const std::vector<StatsLogValue>& getElements() const { return mElements; } - - const std::vector<WorkChain>& getWorkChains() const { return mWorkChains; } - - private: - int mTagId; - - int64_t mElapsedRealTimeNs; - - int64_t mWallClockTimeNs; - - std::vector<StatsLogValue> mElements; - - std::vector<WorkChain> mWorkChains; -}; -} // Namespace os -} // Namespace android - - -#endif // STATS_LOG_EVENT_WRAPPER_H - diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp deleted file mode 100644 index f6dfdef16e19..000000000000 --- a/libs/services/src/os/StatsLogEventWrapper.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include <android/os/StatsLogEventWrapper.h> - -#include <binder/Parcel.h> -#include <binder/Parcelable.h> -#include <binder/Status.h> -#include <utils/RefBase.h> -#include <vector> - -using android::Parcel; -using android::Parcelable; -using android::status_t; -using std::vector; - -namespace android { -namespace os { - -StatsLogEventWrapper::StatsLogEventWrapper(){}; - -status_t StatsLogEventWrapper::writeToParcel(Parcel* out) const { - // Implement me if desired. We don't currently use this. - ALOGE( - "Cannot do c++ StatsLogEventWrapper.writeToParcel(); it is not " - "implemented."); - (void)out; // To prevent compile error of unused parameter 'in' - return UNKNOWN_ERROR; -}; - -status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) { - status_t res = OK; - if (in == NULL) { - ALOGE("statsd received parcel argument was NULL."); - return BAD_VALUE; - } - if ((res = in->readInt32(&mTagId)) != OK) { - ALOGE("statsd could not read tagId from parcel"); - return res; - } - if ((res = in->readInt64(&mElapsedRealTimeNs)) != OK) { - ALOGE("statsd could not read elapsed real time from parcel"); - return res; - } - if ((res = in->readInt64(&mWallClockTimeNs)) != OK) { - ALOGE("statsd could not read wall clock time from parcel"); - return res; - } - int numWorkChain = 0; - if ((res = in->readInt32(&numWorkChain)) != OK) { - ALOGE("statsd could not read number of work chains from parcel"); - return res; - } - if (numWorkChain > 0) { - for (int i = 0; i < numWorkChain; i++) { - int numNodes = 0; - if ((res = in->readInt32(&numNodes)) != OK) { - ALOGE( - "statsd could not read number of nodes in work chain from parcel"); - return res; - } - if (numNodes == 0) { - ALOGE("empty work chain"); - return BAD_VALUE; - } - WorkChain wc; - for (int j = 0; j < numNodes; j++) { - wc.uids.push_back(in->readInt32()); - wc.tags.push_back(std::string(String8(in->readString16()).string())); - } - mWorkChains.push_back(wc); - } - } - int dataSize = 0; - if ((res = in->readInt32(&dataSize)) != OK) { - ALOGE("statsd could not read data size from parcel"); - return res; - } - if (mTagId <= 0 || mElapsedRealTimeNs <= 0 || mWallClockTimeNs <= 0 || - dataSize <= 0) { - ALOGE("statsd received invalid parcel"); - return BAD_VALUE; - } - - for (int i = 0; i < dataSize; i++) { - int type = in->readInt32(); - switch (type) { - case StatsLogValue::INT: - mElements.push_back(StatsLogValue(in->readInt32())); - break; - case StatsLogValue::LONG: - mElements.push_back(StatsLogValue(in->readInt64())); - break; - case StatsLogValue::STRING: - mElements.push_back( - StatsLogValue(std::string(String8(in->readString16()).string()))); - break; - case StatsLogValue::FLOAT: - mElements.push_back(StatsLogValue(in->readFloat())); - break; - case StatsLogValue::STORAGE: - mElements.push_back(StatsLogValue()); - mElements.back().setType(StatsLogValue::STORAGE); - in->readByteVector(&(mElements.back().storage_value)); - break; - default: - ALOGE("unrecognized data type: %d", type); - return BAD_TYPE; - } - } - return NO_ERROR; -}; - -} // Namespace os -} // Namespace android diff --git a/location/java/android/location/GnssMeasurementCorrections.java b/location/java/android/location/GnssMeasurementCorrections.java index a23213ff260c..19c3992ebed3 100644 --- a/location/java/android/location/GnssMeasurementCorrections.java +++ b/location/java/android/location/GnssMeasurementCorrections.java @@ -79,6 +79,25 @@ public final class GnssMeasurementCorrections implements Parcelable { @NonNull private final List<GnssSingleSatCorrection> mSingleSatCorrectionList; + /** + * Indicates whether the environment bearing is available. + */ + private final boolean mHasEnvironmentBearing; + + /** + * Environment bearing in degrees clockwise from true north, in the direction of user motion. + * Environment bearing is provided when it is known with high probability that velocity is + * aligned with an environment feature (such as edge of a building, or road). + */ + @FloatRange(from = 0.0f, to = 360.0f) + private final float mEnvironmentBearingDegrees; + + /** + * Environment bearing uncertainty in degrees. + */ + @FloatRange(from = 0.0f, to = 180.0f) + private final float mEnvironmentBearingUncertaintyDegrees; + private GnssMeasurementCorrections(Builder builder) { mLatitudeDegrees = builder.mLatitudeDegrees; mLongitudeDegrees = builder.mLongitudeDegrees; @@ -89,6 +108,10 @@ public final class GnssMeasurementCorrections implements Parcelable { final List<GnssSingleSatCorrection> singleSatCorrList = builder.mSingleSatCorrectionList; Preconditions.checkArgument(singleSatCorrList != null && !singleSatCorrList.isEmpty()); mSingleSatCorrectionList = Collections.unmodifiableList(new ArrayList<>(singleSatCorrList)); + mHasEnvironmentBearing = builder.mEnvironmentBearingIsSet + && builder.mEnvironmentBearingUncertaintyIsSet; + mEnvironmentBearingDegrees = builder.mEnvironmentBearingDegrees; + mEnvironmentBearingUncertaintyDegrees = builder.mEnvironmentBearingUncertaintyDegrees; } /** Gets the latitude in degrees at which the corrections are computed. */ @@ -145,6 +168,31 @@ public final class GnssMeasurementCorrections implements Parcelable { return mSingleSatCorrectionList; } + /** + * If true, environment bearing will be available. + */ + public boolean hasEnvironmentBearing() { + return mHasEnvironmentBearing; + } + + /** + * Gets the environment bearing in degrees clockwise from true north, in the direction of user + * motion. Environment bearing is provided when it is known with high probability that + * velocity is aligned with an environment feature (such as edge of a building, or road). + */ + @FloatRange(from = 0.0f, to = 360.0f) + public float getEnvironmentBearingDegrees() { + return mEnvironmentBearingDegrees; + } + + /** + * Gets the environment bearing uncertainty in degrees. + */ + @FloatRange(from = 0.0f, to = 180.0f) + public float getEnvironmentBearingUncertaintyDegrees() { + return mEnvironmentBearingUncertaintyDegrees; + } + @Override public int describeContents() { return 0; @@ -167,6 +215,12 @@ public final class GnssMeasurementCorrections implements Parcelable { parcel.readTypedList(singleSatCorrectionList, GnssSingleSatCorrection.CREATOR); gnssMeasurementCorrectons.setSingleSatelliteCorrectionList( singleSatCorrectionList); + boolean hasEnvironmentBearing = parcel.readBoolean(); + if (hasEnvironmentBearing) { + gnssMeasurementCorrectons.setEnvironmentBearingDegrees(parcel.readFloat()); + gnssMeasurementCorrectons.setEnvironmentBearingUncertaintyDegrees( + parcel.readFloat()); + } return gnssMeasurementCorrectons.build(); } @@ -192,6 +246,14 @@ public final class GnssMeasurementCorrections implements Parcelable { String.format(format, "ToaGpsNanosecondsOfWeek = ", mToaGpsNanosecondsOfWeek)); builder.append( String.format(format, "mSingleSatCorrectionList = ", mSingleSatCorrectionList)); + builder.append( + String.format(format, "HasEnvironmentBearing = ", mHasEnvironmentBearing)); + builder.append( + String.format(format, "EnvironmentBearingDegrees = ", + mEnvironmentBearingDegrees)); + builder.append( + String.format(format, "EnvironmentBearingUncertaintyDegrees = ", + mEnvironmentBearingUncertaintyDegrees)); return builder.toString(); } @@ -204,6 +266,11 @@ public final class GnssMeasurementCorrections implements Parcelable { parcel.writeDouble(mVerticalPositionUncertaintyMeters); parcel.writeLong(mToaGpsNanosecondsOfWeek); parcel.writeTypedList(mSingleSatCorrectionList); + parcel.writeBoolean(mHasEnvironmentBearing); + if (mHasEnvironmentBearing) { + parcel.writeFloat(mEnvironmentBearingDegrees); + parcel.writeFloat(mEnvironmentBearingUncertaintyDegrees); + } } /** Builder for {@link GnssMeasurementCorrections} */ @@ -219,6 +286,10 @@ public final class GnssMeasurementCorrections implements Parcelable { private double mVerticalPositionUncertaintyMeters; private long mToaGpsNanosecondsOfWeek; @Nullable private List<GnssSingleSatCorrection> mSingleSatCorrectionList; + private float mEnvironmentBearingDegrees; + private boolean mEnvironmentBearingIsSet = false; + private float mEnvironmentBearingUncertaintyDegrees; + private boolean mEnvironmentBearingUncertaintyIsSet = false; /** Sets the latitude in degrees at which the corrections are computed. */ @NonNull public Builder setLatitudeDegrees( @@ -282,8 +353,37 @@ public final class GnssMeasurementCorrections implements Parcelable { return this; } + /** + * Sets the environment bearing in degrees clockwise from true north, in the direction of + * user motion. Environment bearing is provided when it is known with high probability + * that velocity is aligned with an environment feature (such as edge of a building, or + * road). + */ + @NonNull public Builder setEnvironmentBearingDegrees( + @FloatRange(from = 0.0f, to = 360.0f) + float environmentBearingDegrees) { + mEnvironmentBearingDegrees = environmentBearingDegrees; + mEnvironmentBearingIsSet = true; + return this; + } + + /** + * Sets the environment bearing uncertainty in degrees. + */ + @NonNull public Builder setEnvironmentBearingUncertaintyDegrees( + @FloatRange(from = 0.0f, to = 180.0f) + float environmentBearingUncertaintyDegrees) { + mEnvironmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegrees; + mEnvironmentBearingUncertaintyIsSet = true; + return this; + } + /** Builds a {@link GnssMeasurementCorrections} instance as specified by this builder. */ @NonNull public GnssMeasurementCorrections build() { + if (mEnvironmentBearingIsSet ^ mEnvironmentBearingUncertaintyIsSet) { + throw new IllegalStateException("Both environment bearing and environment bearing " + + "uncertainty must be set."); + } return new GnssMeasurementCorrections(this); } } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 687535c3304b..0c5fe787bbbc 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -74,7 +74,7 @@ import java.util.function.Consumer; * still return location results, but the exact location will be obfuscated to a coarse level of * accuracy. */ -@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"}) +@SuppressWarnings({"deprecation"}) @SystemService(Context.LOCATION_SERVICE) @RequiresFeature(PackageManager.FEATURE_LOCATION) public class LocationManager { diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java new file mode 100644 index 000000000000..44d9d2372665 --- /dev/null +++ b/location/java/android/location/LocationManagerInternal.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 android.location; + + +import android.annotation.NonNull; + +/** + * Location manager local system service interface. + * + * @hide Only for use within the system server. + */ +public abstract class LocationManagerInternal { + + /** + * Requests that a provider change its allowed state. A provider may or may not honor this + * request, and if the provider does change its state as a result, that may happen + * asynchronously after some delay. + * + * <p>Setting a provider's state to allowed implies that any consents or terms and conditions + * that may be necessary to allow the provider are agreed to. Setting a providers state to + * disallowed implies that any consents or terms and conditions have their agreement revoked. + * + * @param provider A location provider as listed by {@link LocationManager#getAllProviders()} + * @param allowed Whether the location provider is being requested to allow or disallow + * itself + * @throws IllegalArgumentException if provider is null + */ + public abstract void requestSetProviderAllowed(@NonNull String provider, boolean allowed); +} diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl index 4246c6cd1004..b7817ff1e1fc 100644 --- a/location/java/com/android/internal/location/ILocationProvider.aidl +++ b/location/java/com/android/internal/location/ILocationProvider.aidl @@ -37,4 +37,6 @@ interface ILocationProvider { @UnsupportedAppUsage oneway void sendExtraCommand(String command, in Bundle extras); + + oneway void requestSetAllowed(boolean allowed); } diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl index 85e18ba5ec4b..439039148773 100644 --- a/location/java/com/android/internal/location/ILocationProviderManager.aidl +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -29,7 +29,7 @@ interface ILocationProviderManager { void onSetAdditionalProviderPackages(in List<String> packageNames); @UnsupportedAppUsage - void onSetEnabled(boolean enabled); + void onSetAllowed(boolean allowed); @UnsupportedAppUsage void onSetProperties(in ProviderProperties properties); diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index 5471bea549f4..49fcaabe981a 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -9,18 +9,21 @@ package com.android.location.provider { public abstract class LocationProviderBase { ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); method public android.os.IBinder getBinder(); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); + method @RequiresApi(android.os.Build.VERSION_CODES.R) public boolean isAllowed(); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); method @Deprecated protected void onDisable(); method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]); method @Deprecated protected void onEnable(); method @Deprecated protected int onGetStatus(android.os.Bundle); method @Deprecated protected long onGetStatusUpdateTime(); method protected void onInit(); + method protected void onRequestSetAllowed(boolean); method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle); method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public void reportLocation(android.location.Location); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); + method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; field public static final String FUSED_PROVIDER = "fused"; diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index fc7bff3c6dab..f67d08e045e2 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -92,7 +92,7 @@ public abstract class LocationProviderBase { // write locked on mBinder, read lock is optional depending on atomicity requirements @Nullable private volatile ILocationProviderManager mManager; private volatile ProviderProperties mProperties; - private volatile boolean mEnabled; + private volatile boolean mAllowed; private final ArrayList<String> mAdditionalProviderPackages; public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { @@ -104,7 +104,7 @@ public abstract class LocationProviderBase { mManager = null; mProperties = properties.getProviderProperties(); - mEnabled = true; + mAllowed = true; mAdditionalProviderPackages = new ArrayList<>(0); } @@ -113,35 +113,44 @@ public abstract class LocationProviderBase { } /** - * Sets whether this provider is currently enabled or not. Note that this is specific to the + * @deprecated Use {@link #setAllowed(boolean)} instead. + */ + @Deprecated + @RequiresApi(VERSION_CODES.Q) + public void setEnabled(boolean enabled) { + setAllowed(enabled); + } + + /** + * Sets whether this provider is currently allowed or not. Note that this is specific to the * provider only, and is not related to global location settings. This is a hint to the Location * Manager that this provider will generally be unable to fulfill incoming requests. This - * provider may still receive callbacks to onSetRequest while not enabled, and must decide + * provider may still receive callbacks to onSetRequest while not allowed, and must decide * whether to attempt to satisfy those requests or not. * - * Some guidelines: providers should set their own enabled/disabled status based only on state - * "owned" by that provider. For instance, providers should not take into account the state of - * the location master setting when setting themselves enabled or disabled, as this state is not - * owned by a particular provider. If a provider requires some additional user consent that is - * particular to the provider, this should be use to set the enabled/disabled state. If the - * provider proxies to another provider, the child provider's enabled/disabled state should be - * taken into account in the parent's enabled/disabled state. For most providers, it is expected - * that they will be always enabled. + * <p>Some guidelines: providers should set their own allowed/disallowed status based only on + * state "owned" by that provider. For instance, providers should not take into account the + * state of the location master setting when setting themselves allowed or disallowed, as this + * state is not owned by a particular provider. If a provider requires some additional user + * consent that is particular to the provider, this should be use to set the allowed/disallowed + * state. If the provider proxies to another provider, the child provider's allowed/disallowed + * state should be taken into account in the parent's allowed state. For most providers, it is + * expected that they will be always allowed. */ - @RequiresApi(VERSION_CODES.Q) - public void setEnabled(boolean enabled) { + @RequiresApi(VERSION_CODES.R) + public void setAllowed(boolean allowed) { synchronized (mBinder) { - if (mEnabled == enabled) { + if (mAllowed == allowed) { return; } - mEnabled = enabled; + mAllowed = allowed; } ILocationProviderManager manager = mManager; if (manager != null) { try { - manager.onSetEnabled(mEnabled); + manager.onSetAllowed(mAllowed); } catch (RemoteException | RuntimeException e) { Log.w(mTag, e); } @@ -193,12 +202,20 @@ public abstract class LocationProviderBase { } /** - * Returns true if this provider has been set as enabled. This will be true unless explicitly - * set otherwise. + * @deprecated Use {@link #isAllowed()} instead. */ + @Deprecated @RequiresApi(VERSION_CODES.Q) public boolean isEnabled() { - return mEnabled; + return isAllowed(); + } + + /** + * Returns true if this provider is allowed. Providers start as allowed on construction. + */ + @RequiresApi(VERSION_CODES.R) + public boolean isAllowed() { + return mAllowed; } /** @@ -285,6 +302,17 @@ public abstract class LocationProviderBase { return false; } + /** + * Invoked when the system wishes to request that the provider sets its allowed state as + * desired. This implies that the caller is providing/retracting consent for any terms and + * conditions or consents associated with the provider. + * + * <p>It is generally only necessary to override this function if the provider has some barriers + * or gates for enabling/disabling itself, in which case this function should handle those + * appropriately. A provider that is always allowed has no need to override this function. + */ + protected void onRequestSetAllowed(boolean allowed) {} + private final class Service extends ILocationProvider.Stub { @Override @@ -295,7 +323,7 @@ public abstract class LocationProviderBase { manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); } manager.onSetProperties(mProperties); - manager.onSetEnabled(mEnabled); + manager.onSetAllowed(mAllowed); } catch (RemoteException e) { Log.w(mTag, e); } @@ -315,5 +343,10 @@ public abstract class LocationProviderBase { public void sendExtraCommand(String command, Bundle extras) { onSendExtraCommand(command, extras); } + + @Override + public void requestSetAllowed(boolean allowed) { + onRequestSetAllowed(allowed); + } } } diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index cbc9683b9cc1..197786f42490 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -763,7 +763,13 @@ public final class MediaCodecInfo { int maxLevel = 0; for (CodecProfileLevel pl : profileLevels) { if (pl.profile == profile && pl.level > maxLevel) { - maxLevel = pl.level; + // H.263 levels are not completely ordered: + // Level45 support only implies Level10 support + if (!mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263) + || pl.level != CodecProfileLevel.H263Level45 + || maxLevel == CodecProfileLevel.H263Level10) { + maxLevel = pl.level; + } } } levelCaps = createFromProfileLevel(mMime, profile, maxLevel); diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index ab6966d5d1c3..9b37f955fa17 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1750,22 +1750,150 @@ static void android_media_MediaCodec_queueSecureInputBuffer( return; } - NativeCryptoInfo cryptoInfo{env, cryptoInfoObj}; + jint numSubSamples = + env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); + + jintArray numBytesOfClearDataObj = + (jintArray)env->GetObjectField( + cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); + + jintArray numBytesOfEncryptedDataObj = + (jintArray)env->GetObjectField( + cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); + + jbyteArray keyObj = + (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); + + jbyteArray ivObj = + (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); + + jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); + enum CryptoPlugin::Mode mode; + if (jmode == gCryptoModes.Unencrypted) { + mode = CryptoPlugin::kMode_Unencrypted; + } else if (jmode == gCryptoModes.AesCtr) { + mode = CryptoPlugin::kMode_AES_CTR; + } else if (jmode == gCryptoModes.AesCbc) { + mode = CryptoPlugin::kMode_AES_CBC; + } else { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID); + + CryptoPlugin::Pattern pattern; + if (patternObj == NULL) { + pattern.mEncryptBlocks = 0; + pattern.mSkipBlocks = 0; + } else { + pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID); + pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID); + } + + status_t err = OK; + + CryptoPlugin::SubSample *subSamples = NULL; + jbyte *key = NULL; + jbyte *iv = NULL; + + if (numSubSamples <= 0) { + err = -EINVAL; + } else if (numBytesOfClearDataObj == NULL + && numBytesOfEncryptedDataObj == NULL) { + err = -EINVAL; + } else if (numBytesOfEncryptedDataObj != NULL + && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { + err = -ERANGE; + } else if (numBytesOfClearDataObj != NULL + && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { + err = -ERANGE; + // subSamples array may silently overflow if number of samples are too large. Use + // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms + } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { + err = -EINVAL; + } else { + jboolean isCopy; + + jint *numBytesOfClearData = + (numBytesOfClearDataObj == NULL) + ? NULL + : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); + + jint *numBytesOfEncryptedData = + (numBytesOfEncryptedDataObj == NULL) + ? NULL + : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); + + subSamples = new CryptoPlugin::SubSample[numSubSamples]; + + for (jint i = 0; i < numSubSamples; ++i) { + subSamples[i].mNumBytesOfClearData = + (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; + + subSamples[i].mNumBytesOfEncryptedData = + (numBytesOfEncryptedData == NULL) + ? 0 : numBytesOfEncryptedData[i]; + } + + if (numBytesOfEncryptedData != NULL) { + env->ReleaseIntArrayElements( + numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); + numBytesOfEncryptedData = NULL; + } + + if (numBytesOfClearData != NULL) { + env->ReleaseIntArrayElements( + numBytesOfClearDataObj, numBytesOfClearData, 0); + numBytesOfClearData = NULL; + } + } + + if (err == OK && keyObj != NULL) { + if (env->GetArrayLength(keyObj) != 16) { + err = -EINVAL; + } else { + jboolean isCopy; + key = env->GetByteArrayElements(keyObj, &isCopy); + } + } + + if (err == OK && ivObj != NULL) { + if (env->GetArrayLength(ivObj) != 16) { + err = -EINVAL; + } else { + jboolean isCopy; + iv = env->GetByteArrayElements(ivObj, &isCopy); + } + } + AString errorDetailMsg; - status_t err = cryptoInfo.mErr; if (err == OK) { err = codec->queueSecureInputBuffer( index, offset, - cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples, - (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv, - cryptoInfo.mMode, - cryptoInfo.mPattern, + subSamples, numSubSamples, + (const uint8_t *)key, (const uint8_t *)iv, + mode, + pattern, timestampUs, flags, &errorDetailMsg); } + if (iv != NULL) { + env->ReleaseByteArrayElements(ivObj, iv, 0); + iv = NULL; + } + + if (key != NULL) { + env->ReleaseByteArrayElements(keyObj, key, 0); + key = NULL; + } + + delete[] subSamples; + subSamples = NULL; + throwExceptionAsNecessary( env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); } diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index 0be2514a7936..aa3279321e90 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -13,6 +13,7 @@ cc_library_shared { header_libs: [ "libmedia_headers", + "libmediametrics_headers", ], shared_libs: [ diff --git a/media/jni/soundpool/tests/Android.bp b/media/jni/soundpool/tests/Android.bp index 96ec4e5d5913..52f59ed69503 100644 --- a/media/jni/soundpool/tests/Android.bp +++ b/media/jni/soundpool/tests/Android.bp @@ -16,6 +16,10 @@ cc_binary { "libutils", ], + header_libs: [ + "libmediametrics_headers", + ], + srcs: [ "soundpool_stress.cpp" ], diff --git a/media/tests/audiotests/Android.bp b/media/tests/audiotests/Android.bp index 8ef7694132de..5db0ab0cde6d 100644 --- a/media/tests/audiotests/Android.bp +++ b/media/tests/audiotests/Android.bp @@ -14,6 +14,10 @@ cc_test { "libaudioclient", ], + header_libs: [ + "libmediametrics_headers", + ], + cflags: [ "-Wall", "-Werror", diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp index 79bcc15e1f0f..c1143ce9c3dc 100644 --- a/native/graphics/jni/imagedecoder.cpp +++ b/native/graphics/jni/imagedecoder.cpp @@ -325,11 +325,9 @@ int AImageDecoder_decodeImage(AImageDecoder* decoder, ImageDecoder* imageDecoder = toDecoder(decoder); - const int height = imageDecoder->getOutputInfo().height(); - const size_t minStride = AImageDecoder_getMinimumStride(decoder); - // If this calculation were to overflow, it would have been caught in - // setTargetSize. - if (stride < minStride || size < stride * (height - 1) + minStride) { + SkImageInfo info = imageDecoder->getOutputInfo(); + size_t minSize = info.computeByteSize(stride); + if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) { return ANDROID_IMAGE_DECODER_BAD_PARAMETER; } diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 981c129a0965..e2297e44fdfe 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -80,5 +80,6 @@ <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> <item>com.android.systemui.theme.ThemeOverlayController</item> <item>com.android.systemui.navigationbar.car.CarNavigationBar</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> </resources> diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java index 33126510bc53..d1a379afa25e 100644 --- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java +++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java @@ -205,7 +205,7 @@ public class FusedLocationServiceTest { } @Override - public void onSetEnabled(boolean enabled) { + public void onSetAllowed(boolean allowed) { } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 486386f3d284..107207638205 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -4488,7 +4488,7 @@ public class SettingsProvider extends ContentProvider { try { overlayManager.setEnabledExclusiveInCategory( NAV_BAR_MODE_2BUTTON_OVERLAY, UserHandle.USER_CURRENT); - } catch (RemoteException e) { + } catch (SecurityException | IllegalStateException | RemoteException e) { throw new IllegalStateException( "Failed to set nav bar interaction mode overlay"); } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index b896a2a8d9a4..6d94a90d2c32 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -31,6 +31,7 @@ import android.provider.settings.backup.SecureSettings; import android.provider.settings.backup.SystemSettings; import androidx.test.filters.SmallTest; +import androidx.test.filters.Suppress; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; @@ -224,6 +225,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, Settings.Global.DEVELOPMENT_FORCE_RTL, Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, + Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, Settings.Global.DEVICE_DEMO_MODE, Settings.Global.DEVICE_IDLE_CONSTANTS, Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS, @@ -277,6 +279,7 @@ public class SettingsBackupTest { Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, Settings.Global.WIFI_ON_WHEN_PROXY_DISCONNECTED, Settings.Global.FSTRIM_MANDATORY_INTERVAL, + Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, Settings.Global.GLOBAL_HTTP_PROXY_HOST, Settings.Global.GLOBAL_HTTP_PROXY_PAC, @@ -574,7 +577,8 @@ public class SettingsBackupTest { Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT, Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT, Settings.Global.POWER_BUTTON_LONG_PRESS, - Settings.Global.POWER_BUTTON_VERY_LONG_PRESS); + Settings.Global.POWER_BUTTON_VERY_LONG_PRESS, + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER); private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS = newHashSet( @@ -746,6 +750,7 @@ public class SettingsBackupTest { } @Test + @Suppress //("b/148236308") public void secureSettingsBackedUpOrBlacklisted() { HashSet<String> keys = new HashSet<String>(); Collections.addAll(keys, SecureSettings.SETTINGS_TO_BACKUP); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index f0dc606658a8..d40e7d4addab 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -243,6 +243,9 @@ <uses-permission android:name="android.permission.READ_DREAM_STATE"/> <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/> + <!-- Permission required for CTS test - CtsLightsManagerTest --> + <uses-permission android:name="android.permission.CONTROL_DEVICE_LIGHTS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 30ad9c5d658c..48d405a4b91f 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -156,7 +156,6 @@ public class BugreportProgressService extends Service { static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE"; static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT"; static final String EXTRA_ID = "android.intent.extra.ID"; - static final String EXTRA_MAX = "android.intent.extra.MAX"; static final String EXTRA_NAME = "android.intent.extra.NAME"; static final String EXTRA_TITLE = "android.intent.extra.TITLE"; static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION"; @@ -173,7 +172,6 @@ public class BugreportProgressService extends Service { // Maximum progress displayed in %. private static final int CAPPED_PROGRESS = 99; - private static final int CAPPED_MAX = 100; /** Show the progress log every this percent. */ private static final int LOG_PROGRESS_STEP = 10; @@ -528,12 +526,10 @@ public class BugreportProgressService extends Service { } final String action = intent.getAction(); final int id = intent.getIntExtra(EXTRA_ID, 0); - final int max = intent.getIntExtra(EXTRA_MAX, -1); final String name = intent.getStringExtra(EXTRA_NAME); if (DEBUG) - Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id - + ", max: " + max); + Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id); switch (action) { case INTENT_BUGREPORT_REQUESTED: startBugreportAPI(intent); @@ -608,7 +604,7 @@ public class BugreportProgressService extends Service { String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); BugreportInfo info = new BugreportInfo(mContext, baseName, name, - 100 /* max progress*/, shareTitle, shareDescription, bugreportType); + shareTitle, shareDescription, bugreportType); ParcelFileDescriptor bugreportFd = info.createBugreportFd(); if (bugreportFd == null) { @@ -662,8 +658,8 @@ public class BugreportProgressService extends Service { * Updates the system notification for a given bugreport. */ private void updateProgress(BugreportInfo info) { - if (info.max <= 0 || info.progress < 0) { - Log.e(TAG, "Invalid progress values for " + info); + if (info.progress < 0) { + Log.e(TAG, "Invalid progress value for " + info); return; } @@ -676,7 +672,7 @@ public class BugreportProgressService extends Service { final NumberFormat nf = NumberFormat.getPercentInstance(); nf.setMinimumFractionDigits(2); nf.setMaximumFractionDigits(2); - final String percentageText = nf.format((double) info.progress / info.max); + final String percentageText = nf.format((double) info.progress / 100); String title = mContext.getString(R.string.bugreport_in_progress_title, info.id); @@ -684,7 +680,7 @@ public class BugreportProgressService extends Service { if (mIsWatch) { nf.setMinimumFractionDigits(0); nf.setMaximumFractionDigits(0); - final String watchPercentageText = nf.format((double) info.progress / info.max); + final String watchPercentageText = nf.format((double) info.progress / 100); title = title + "\n" + watchPercentageText; } @@ -695,7 +691,7 @@ public class BugreportProgressService extends Service { .setContentTitle(title) .setTicker(title) .setContentText(name) - .setProgress(info.max, info.progress, false) + .setProgress(100 /* max value of progress percentage */, info.progress, false) .setOngoing(true); // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action. @@ -724,7 +720,7 @@ public class BugreportProgressService extends Service { .setActions(infoAction, screenshotAction, cancelAction); } // Show a debug log, every LOG_PROGRESS_STEP percent. - final int progress = (info.progress * 100) / info.max; + final int progress = info.progress; if ((info.progress == 0) || (info.progress >= 100) || ((progress / LOG_PROGRESS_STEP) != (mLastProgressPercent / LOG_PROGRESS_STEP))) { @@ -1457,7 +1453,6 @@ public class BugreportProgressService extends Service { } final StringBuilder buffer = new StringBuilder(action).append(" extras: "); addExtra(buffer, intent, EXTRA_ID); - addExtra(buffer, intent, EXTRA_MAX); addExtra(buffer, intent, EXTRA_NAME); addExtra(buffer, intent, EXTRA_DESCRIPTION); addExtra(buffer, intent, EXTRA_BUGREPORT); @@ -1761,26 +1756,11 @@ public class BugreportProgressService extends Service { String description; /** - * Maximum progress of the bugreport generation as displayed by the UI. - */ - int max; - - /** - * Current progress of the bugreport generation as displayed by the UI. + * Current progress (in percentage) of the bugreport generation as displayed by the UI. */ int progress; /** - * Maximum progress of the bugreport generation as reported by dumpstate. - */ - int realMax; - - /** - * Current progress of the bugreport generation as reported by dumpstate. - */ - int realProgress; - - /** * Time of the last progress update. */ long lastUpdate = System.currentTimeMillis(); @@ -1831,12 +1811,11 @@ public class BugreportProgressService extends Service { /** * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED. */ - BugreportInfo(Context context, String baseName, String name, int max, + BugreportInfo(Context context, String baseName, String name, @Nullable String shareTitle, @Nullable String shareDescription, @BugreportParams.BugreportMode int type) { this.context = context; this.name = this.initialName = name; - this.max = this.realMax = max; this.shareTitle = shareTitle == null ? "" : shareTitle; this.shareDescription = shareDescription == null ? "" : shareDescription; this.type = type; @@ -1930,8 +1909,6 @@ public class BugreportProgressService extends Service { @Override public String toString() { - final float percent = ((float) progress * 100 / max); - final float realPercent = ((float) realProgress * 100 / realMax); final StringBuilder builder = new StringBuilder() .append("\tid: ").append(id) @@ -1953,10 +1930,7 @@ public class BugreportProgressService extends Service { return builder .append("\n\tfile: ").append(bugreportFile) .append("\n\tscreenshots: ").append(screenshotFiles) - .append("\n\tprogress: ").append(progress).append("/").append(max) - .append(" (").append(percent).append(")") - .append("\n\treal progress: ").append(realProgress).append("/").append(realMax) - .append(" (").append(realPercent).append(")") + .append("\n\tprogress: ").append(progress) .append("\n\tlast_update: ").append(getFormattedLastUpdate()) .append("\n\taddingDetailsToZip: ").append(addingDetailsToZip) .append(" addedDetailsToZip: ").append(addedDetailsToZip) @@ -1974,10 +1948,7 @@ public class BugreportProgressService extends Service { initialName = in.readString(); title = in.readString(); description = in.readString(); - max = in.readInt(); progress = in.readInt(); - realMax = in.readInt(); - realProgress = in.readInt(); lastUpdate = in.readLong(); formattedLastUpdate = in.readString(); bugreportFile = readFile(in); @@ -2001,10 +1972,7 @@ public class BugreportProgressService extends Service { dest.writeString(initialName); dest.writeString(title); dest.writeString(description); - dest.writeInt(max); dest.writeInt(progress); - dest.writeInt(realMax); - dest.writeInt(realProgress); dest.writeLong(lastUpdate); dest.writeString(getFormattedLastUpdate()); writeFile(dest, bugreportFile); @@ -2055,22 +2023,13 @@ public class BugreportProgressService extends Service { if (progress > CAPPED_PROGRESS) { progress = CAPPED_PROGRESS; } - updateProgressInfo(info, progress, CAPPED_MAX); - } - - private void updateProgressInfo(BugreportInfo info, int progress, int max) { if (DEBUG) { if (progress != info.progress) { Log.v(TAG, "Updating progress for name " + info.name + "(id: " + info.id + ") from " + info.progress + " to " + progress); } - if (max != info.max) { - Log.v(TAG, "Updating max progress for name " + info.name + "(id: " + info.id - + ") from " + info.max + " to " + max); - } } info.progress = progress; - info.max = max; info.lastUpdate = System.currentTimeMillis(); updateProgress(info); diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index bb298e937fbb..b95092a9384c 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -27,7 +27,6 @@ import static com.android.shell.BugreportPrefs.getWarningState; import static com.android.shell.BugreportPrefs.setWarningState; import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT; import static com.android.shell.BugreportProgressService.EXTRA_ID; -import static com.android.shell.BugreportProgressService.EXTRA_MAX; import static com.android.shell.BugreportProgressService.EXTRA_NAME; import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT; import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED; @@ -144,6 +143,7 @@ public class BugreportReceiverTest { private static final String DESCRIPTION = "One's description..."; private static final String DESCRIPTION2 = "...is another's treasure."; // TODO(b/143130523): Fix (update) tests and add to presubmit + private static final String EXTRA_MAX = "android.intent.extra.MAX"; private static final String EXTRA_PID = "android.intent.extra.PID"; private static final String INTENT_BUGREPORT_STARTED = "com.android.internal.intent.action.BUGREPORT_STARTED"; diff --git a/packages/SystemUI/res/color/light_background.xml b/packages/SystemUI/res/color/light_background.xml new file mode 100644 index 000000000000..2effd991f666 --- /dev/null +++ b/packages/SystemUI/res/color/light_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_yellow_50" /> +</selector> diff --git a/packages/SystemUI/res/color/light_foreground.xml b/packages/SystemUI/res/color/light_foreground.xml new file mode 100644 index 000000000000..8143028795df --- /dev/null +++ b/packages/SystemUI/res/color/light_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_orange_900" /> +</selector> diff --git a/packages/SystemUI/res/color/lock_background.xml b/packages/SystemUI/res/color/lock_background.xml new file mode 100644 index 000000000000..646fe5dfe712 --- /dev/null +++ b/packages/SystemUI/res/color/lock_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_blue_50" /> +</selector> diff --git a/packages/SystemUI/res/color/lock_foreground.xml b/packages/SystemUI/res/color/lock_foreground.xml new file mode 100644 index 000000000000..3e05653bce92 --- /dev/null +++ b/packages/SystemUI/res/color/lock_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_blue_700" /> +</selector> diff --git a/packages/SystemUI/res/color/unknown_foreground.xml b/packages/SystemUI/res/color/unknown_foreground.xml new file mode 100644 index 000000000000..bf028f18a7de --- /dev/null +++ b/packages/SystemUI/res/color/unknown_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_blue_700" /> + </selector> diff --git a/packages/SystemUI/res/drawable/control_background.xml b/packages/SystemUI/res/drawable/control_background.xml new file mode 100644 index 000000000000..b246ea0a3935 --- /dev/null +++ b/packages/SystemUI/res/drawable/control_background.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* 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. +*/ +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <solid android:color="?android:attr/colorBackgroundFloating"/> + <corners android:radius="@dimen/control_corner_radius" /> + </shape> + </item> + <item + android:id="@+id/clip_layer"> + <clip + android:clipOrientation="horizontal" + android:drawable="@drawable/control_layer"/> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/control_layer.xml b/packages/SystemUI/res/drawable/control_layer.xml new file mode 100644 index 000000000000..fe8c4a4af1bb --- /dev/null +++ b/packages/SystemUI/res/drawable/control_layer.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* 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. +*/ +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@android:color/transparent"/> + <corners android:radius="@dimen/control_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml new file mode 100644 index 000000000000..1e282ad0eec7 --- /dev/null +++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* 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. +*/ +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <stroke android:width="1dp" android:color="?android:attr/colorBackgroundFloating"/> + <corners android:radius="@dimen/control_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml new file mode 100644 index 000000000000..45a658fe07da --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,9h-5v2h5m3,-6h-8v2h8m-9,11.97c0.62,-0.83 1,-1.85 1,-2.97 0,-1.63 -0.79,-3.09 -2,-4V6c0,-1.66 -1.34,-3 -3,-3S5,4.34 5,6v6c-1.21,0.91 -2,2.37 -2,4 0,1.12 0.38,2.14 1,2.97V19h0.02c0.91,1.21 2.35,2 3.98,2s3.06,-0.79 3.98,-2H12v-0.03zM6.2,13.6L7,13V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v7l0.8,0.6c0.75,0.57 1.2,1.46 1.2,2.4H5c0,-0.94 0.45,-1.84 1.2,-2.4z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml new file mode 100644 index 000000000000..78c3cc54f022 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M9,21v-1h6v1c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1z"/> + <group> + <clip-path android:pathData="M0,0h24v24H0z M 0,0"/> + </group> + <path + android:fillColor="#FF000000" + android:pathData="M12,2c-1.89,0 -3.6,0.75 -4.86,1.97l1.41,1.41C9.45,4.53 10.67,4 12,4c2.76,0 5,2.24 5,5 0,1.28 -0.5,2.5 -1.36,3.42l-0.02,0.02 1.41,1.41C18.25,12.6 19,10.89 19,9c0,-3.86 -3.14,-7 -7,-7z" + android:fillType="evenOdd"/> + <path + android:fillColor="#FF000000" + android:pathData="M2.92,2.29L1.65,3.57l3.59,3.59C5.09,7.75 5,8.36 5,9c0,2.38 1.19,4.47 3,5.74V17c0,0.55 0.45,1 1,1h6c0.3,0 0.57,-0.13 0.75,-0.34L20.09,22l1.27,-1.27L2.92,2.29zM10,16v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9v-0.08L14.09,16H10z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml new file mode 100644 index 000000000000..f4299e6cda11 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml new file mode 100644 index 000000000000..59fe0a914656 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml @@ -0,0 +1,12 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h2c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/> + <path + android:fillColor="#FF000000" + android:pathData="M12,15m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_more_vert.xml b/packages/SystemUI/res/drawable/ic_more_vert.xml new file mode 100644 index 000000000000..1309fa875b55 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_more_vert.xml @@ -0,0 +1,24 @@ +<!-- + 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 xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml new file mode 100644 index 000000000000..cd957196e4dc --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M16,9v4.66l-3.5,3.51V19h-1v-1.83L8,13.65V9h8m0,-6h-2v4h-4V3H8v4h-0.01C6.9,6.99 6,7.89 6,8.98v5.52L9.5,18v3h5v-3l3.5,-3.51V9c0,-1.1 -0.9,-2 -2,-2V3z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml new file mode 100644 index 000000000000..3eb7dd637abe --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M21.19,21.19L2.81,2.81 1.39,4.22l4.63,4.63L6,14.5 9.5,18v3h5v-3l0.34,-0.34 4.94,4.94 1.41,-1.41zM12.5,17.17L12.5,19h-1v-1.83L8,13.65v-2.83l5.42,5.42 -0.92,0.93zM11.83,9L8,5.17L8,3h2v4h4L14,3h2v4c1.1,0 2,0.9 2,2v5.49l-0.34,0.34L16,13.17L16,9h-4.17z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml new file mode 100644 index 000000000000..f4edd875ddff --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M11,2h2v10h-2zM18.37,5.64l-1.41,1.41c2.73,2.73 2.72,7.16 -0.01,9.89 -2.73,2.73 -7.17,2.73 -9.89,0.01 -2.73,-2.73 -2.74,-7.18 -0.01,-9.91l-1.41,-1.4c-3.51,3.51 -3.51,9.21 0.01,12.73 3.51,3.51 9.21,3.51 12.72,-0.01 3.51,-3.51 3.51,-9.2 0,-12.72z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml new file mode 100644 index 000000000000..bb535ceaed8c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M19,9h-8.02C10.06,7.79 8.63,7 7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5c1.63,0 3.06,-0.79 3.98,-2H19c1.66,0 3,-1.34 3,-3S20.66,9 19,9zM19,13h-7.1c0.07,-0.32 0.1,-0.66 0.1,-1s-0.04,-0.68 -0.1,-1H19c0.55,0 1,0.45 1,1S19.55,13 19,13z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml new file mode 100644 index 000000000000..86b9591238f1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M4,16c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM4,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM23,20v2h-7v-2h2.49L12.01,4.59C11.6,3.63 10.66,3 9.61,3 8.17,3 7,4.17 7,5.61L7,9h2c2.21,0 4,1.79 4,4v9L7.99,22c0.44,-0.58 0.76,-1.26 0.91,-2L11,20v-7c0,-1.1 -0.9,-2 -2,-2L4,11v3c-0.71,0 -1.39,0.15 -2,0.42L2,9h3L5,5.61C5,3.07 7.07,1 9.61,1c1.86,0 3.53,1.11 4.25,2.82L20.66,20L23,20z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml new file mode 100644 index 000000000000..687c9c417fa6 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,10.48L18,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l4,3.98v-11l-4,3.98zM16,9.69L16,18L4,18L4,6h12v3.69z"/> +</vector> diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml new file mode 100644 index 000000000000..3c4c61e30bc1 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -0,0 +1,79 @@ +<?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. +--> +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="@dimen/control_height" + android:padding="@dimen/control_padding" + android:clickable="true" + android:focusable="true" + android:layout_marginLeft="3dp" + android:layout_marginRight="3dp" + android:background="@drawable/control_background"> + + <ImageView + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/control_status_normal" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:paddingLeft="3dp" + app:layout_constraintBottom_toBottomOf="@+id/icon" + app:layout_constraintStart_toEndOf="@+id/icon" /> + + <TextView + android:id="@+id/status_extra" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/control_status_normal" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:paddingLeft="3dp" + app:layout_constraintBottom_toBottomOf="@+id/icon" + app:layout_constraintStart_toEndOf="@+id/status" /> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintBottom_toTopOf="@+id/subtitle" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/icon" /> + + <TextView + android:id="@+id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textColor="?android:attr/textColorSecondary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml new file mode 100644 index 000000000000..79672caed61b --- /dev/null +++ b/packages/SystemUI/res/layout/controls_no_favorites.xml @@ -0,0 +1,18 @@ +<merge + xmlns:android="http://schemas.android.com/apk/res/android"> + <TextView + android:id="@+id/controls_title" + android:text="@string/quick_controls_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:gravity="center" + android:textSize="25dp" + android:paddingTop="40dp" + android:paddingBottom="40dp" + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + android:background="@drawable/control_no_favorites_background"/> +</merge> diff --git a/packages/SystemUI/res/layout/controls_row.xml b/packages/SystemUI/res/layout/controls_row.xml new file mode 100644 index 000000000000..13a6b36accd3 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_row.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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/control_spacing" /> diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml new file mode 100644 index 000000000000..7804fe6b6272 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -0,0 +1,35 @@ +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:text="@string/quick_controls_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:gravity="center" + android:textSize="25dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> + <ImageView + android:id="@+id/controls_more" + android:src="@drawable/ic_more_vert" + android:layout_width="34dp" + android:layout_height="24dp" + android:layout_marginEnd="10dp" + app:layout_constraintEnd_toEndOf="parent"/> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <LinearLayout + android:id="@+id/global_actions_controls_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> +</merge> diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml index 4cfb47e3c642..674148495478 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -111,20 +111,7 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/global_actions_panel"> - <TextView - android:text="Home" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:singleLine="true" - android:gravity="center" - android:textSize="25dp" - android:textColor="?android:attr/textColorPrimary" - android:fontFamily="@*android:string/config_headlineFontFamily" /> - <LinearLayout - android:id="@+id/global_actions_controls_list" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" /> + </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 4cc5a6731108..dd4c3210922a 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -36,5 +36,6 @@ <item>com.android.systemui.SliceBroadcastRelayHandler</item> <item>com.android.systemui.SizeCompatModeActivityController</item> <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 8dd2a8b9d07a..09058f2460cb 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -200,18 +200,28 @@ <color name="GM2_grey_800">#3C4043</color> <color name="GM2_grey_900">#202124</color> + <color name="GM2_red_50">#FCE8E6</color> <color name="GM2_red_300">#F28B82</color> <color name="GM2_red_500">#B71C1C</color> <color name="GM2_red_700">#C5221F</color> + <color name="GM2_blue_50">#E8F0FE</color> <color name="GM2_blue_200">#AECBFA</color> <color name="GM2_blue_300">#8AB4F8</color> + <color name="GM2_blue_500">#FF4285F4</color> <color name="GM2_blue_600">#1A73E8</color> <color name="GM2_blue_700">#1967D2</color> + <color name="GM2_yellow_50">#FEF7E0</color> <color name="GM2_yellow_500">#FFFBBC04</color> + <color name="GM2_green_500">#FF34A853</color> - <color name="GM2_blue_500">#FF4285F4</color> + + <color name="GM2_orange_900">#B06000</color> <color name="magnification_border_color">#FF9900</color> + + <!-- controls --> + <color name="control_default_foreground">?android:attr/textColorPrimary</color> + <color name="control_default_background">?android:attr/colorBackgroundFloating</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index e52010600ab3..2aa6d9512898 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -296,6 +296,8 @@ <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> <item>com.android.systemui.theme.ThemeOverlayController</item> <item>com.android.systemui.accessibility.WindowMagnification</item> + <item>com.android.systemui.accessibility.SystemActions</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> <!-- SystemUI vender service, used in config_systemUIServiceComponents. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 65ca9f2132cd..cc58b2014496 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -96,6 +96,9 @@ <!-- Spacing before the airplane mode icon if there are any icons preceding it. --> <dimen name="status_bar_airplane_spacer_width">4dp</dimen> + <!-- Spacing between system icons. --> + <dimen name="status_bar_system_icon_spacing">0dp</dimen> + <!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. --> <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item> @@ -1178,5 +1181,12 @@ <dimen name="magnifier_up_down_controls_width">45dp</dimen> <dimen name="magnifier_up_down_controls_height">40dp</dimen> + <!-- Home Controls --> + <dimen name="control_spacing">5dp</dimen> + <dimen name="control_corner_radius">15dp</dimen> + <dimen name="control_height">100dp</dimen> + <dimen name="control_padding">15dp</dimen> + <dimen name="control_status_normal">12dp</dimen> + <dimen name="control_status_expanded">18dp</dimen> <dimen name="app_icon_size">32dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 44a7fda6bce3..1f13f8dc02fe 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2546,4 +2546,7 @@ <string name="magnification_window_title">Magnification Window</string> <!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] --> <string name="magnification_controls_title">Magnification Window Controls</string> + + <!-- Quick Controls strings [CHAR LIMIT=30] --> + <string name="quick_controls_title">Quick Controls</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 3ff824374aac..10f59a423805 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -43,7 +43,7 @@ <item name="android:windowIsTranslucent">true</item> <item name="android:windowNoTitle">true</item> <item name="android:windowContentOverlay">@null</item> - <item name="android:windowBackground">@null</item> + <item name="android:windowBackground">@android:color/transparent</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:statusBarColor">@*android:color/transparent</item> <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 98b7e2484478..44a8d3c53db7 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -16,6 +16,7 @@ package com.android.systemui.shared.recents.model; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED; @@ -31,6 +32,7 @@ public class ThumbnailData { public final Bitmap thumbnail; public int orientation; + public int rotation; public Rect insets; public boolean reducedResolution; public boolean isRealSnapshot; @@ -43,6 +45,7 @@ public class ThumbnailData { public ThumbnailData() { thumbnail = null; orientation = ORIENTATION_UNDEFINED; + rotation = ROTATION_UNDEFINED; insets = new Rect(); reducedResolution = false; scale = 1f; @@ -57,6 +60,7 @@ public class ThumbnailData { thumbnail = Bitmap.wrapHardwareBuffer(snapshot.getSnapshot(), snapshot.getColorSpace()); insets = new Rect(snapshot.getContentInsets()); orientation = snapshot.getOrientation(); + rotation = snapshot.getRotation(); reducedResolution = snapshot.isReducedResolution(); scale = snapshot.getScale(); isRealSnapshot = snapshot.isRealSnapshot(); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java new file mode 100644 index 000000000000..7262f8caac89 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -0,0 +1,393 @@ +/* + * 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.accessibility; + +import android.accessibilityservice.AccessibilityService; +import android.app.PendingIntent; +import android.app.RemoteAction; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.drawable.Icon; +import android.hardware.input.InputManager; +import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; +import android.view.Display; +import android.view.IWindowManager; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.R; +import com.android.internal.util.ScreenshotHelper; +import com.android.systemui.Dependency; +import com.android.systemui.SystemUI; +import com.android.systemui.recents.Recents; +import com.android.systemui.statusbar.phone.StatusBar; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Class to register system actions with accessibility framework. + */ +@Singleton +public class SystemActions extends SystemUI { + private static final String TAG = "SystemActions"; + // TODO(b/147916452): add implementation on launcher side to register this action. + + /** + * Action ID to go back. + */ + private static final int SYSTEM_ACTION_ID_BACK = AccessibilityService.GLOBAL_ACTION_BACK; // = 1 + + /** + * Action ID to go home. + */ + private static final int SYSTEM_ACTION_ID_HOME = AccessibilityService.GLOBAL_ACTION_HOME; // = 2 + + /** + * Action ID to toggle showing the overview of recent apps. Will fail on platforms that don't + * show recent apps. + */ + private static final int SYSTEM_ACTION_ID_RECENTS = + AccessibilityService.GLOBAL_ACTION_RECENTS; // = 3 + + /** + * Action ID to open the notifications. + */ + private static final int SYSTEM_ACTION_ID_NOTIFICATIONS = + AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS; // = 4 + + /** + * Action ID to open the quick settings. + */ + private static final int SYSTEM_ACTION_ID_QUICK_SETTINGS = + AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS; // = 5 + + /** + * Action ID to open the power long-press dialog. + */ + private static final int SYSTEM_ACTION_ID_POWER_DIALOG = + AccessibilityService.GLOBAL_ACTION_POWER_DIALOG; // = 6 + + /** + * Action ID to toggle docking the current app's window + */ + private static final int SYSTEM_ACTION_ID_TOGGLE_SPLIT_SCREEN = + AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN; // = 7 + + /** + * Action ID to lock the screen + */ + private static final int SYSTEM_ACTION_ID_LOCK_SCREEN = + AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN; // = 8 + + /** + * Action ID to take a screenshot + */ + private static final int SYSTEM_ACTION_ID_TAKE_SCREENSHOT = + AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; // = 9 + + /** + * Action ID to show accessibility menu + */ + private static final int SYSTEM_ACTION_ID_ACCESSIBILITY_MENU = 10; + + private Recents mRecents; + private StatusBar mStatusBar; + private SystemActionsBroadcastReceiver mReceiver; + + @Inject + public SystemActions(Context context) { + super(context); + mRecents = Dependency.get(Recents.class); + mStatusBar = Dependency.get(StatusBar.class); + mReceiver = new SystemActionsBroadcastReceiver(); + } + + @Override + public void start() { + mContext.registerReceiverForAllUsers(mReceiver, mReceiver.createIntentFilter(), null, null); + + // TODO(b/148087487): update the icon used below to a valid one + RemoteAction actionBack = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_back_label), + mContext.getString(R.string.accessibility_system_action_back_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_BACK)); + RemoteAction actionHome = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_home_label), + mContext.getString(R.string.accessibility_system_action_home_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_HOME)); + + RemoteAction actionRecents = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_recents_label), + mContext.getString(R.string.accessibility_system_action_recents_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_RECENTS)); + + RemoteAction actionNotifications = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_notifications_label), + mContext.getString(R.string.accessibility_system_action_notifications_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_NOTIFICATIONS)); + + RemoteAction actionQuickSettings = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_quick_settings_label), + mContext.getString(R.string.accessibility_system_action_quick_settings_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_QUICK_SETTINGS)); + + RemoteAction actionPowerDialog = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_power_dialog_label), + mContext.getString(R.string.accessibility_system_action_power_dialog_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_POWER_DIALOG)); + + RemoteAction actionToggleSplitScreen = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_toggle_split_screen_label), + mContext.getString(R.string.accessibility_system_action_toggle_split_screen_label), + mReceiver.createPendingIntent( + mContext, + SystemActionsBroadcastReceiver.INTENT_ACTION_TOGGLE_SPLIT_SCREEN)); + + RemoteAction actionLockScreen = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_lock_screen_label), + mContext.getString(R.string.accessibility_system_action_lock_screen_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_LOCK_SCREEN)); + + RemoteAction actionTakeScreenshot = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_screenshot_label), + mContext.getString(R.string.accessibility_system_action_screenshot_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT)); + + RemoteAction actionAccessibilityMenu = new RemoteAction( + Icon.createWithResource(mContext, R.drawable.ic_info), + mContext.getString(R.string.accessibility_system_action_accessibility_menu_label), + mContext.getString(R.string.accessibility_system_action_accessibility_menu_label), + mReceiver.createPendingIntent( + mContext, SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_MENU)); + + AccessibilityManager am = (AccessibilityManager) mContext.getSystemService( + Context.ACCESSIBILITY_SERVICE); + + am.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK); + am.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME); + am.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS); + am.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS); + am.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS); + am.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG); + am.registerSystemAction(actionToggleSplitScreen, SYSTEM_ACTION_ID_TOGGLE_SPLIT_SCREEN); + am.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN); + am.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT); + am.registerSystemAction(actionAccessibilityMenu, SYSTEM_ACTION_ID_ACCESSIBILITY_MENU); + } + + private void handleBack() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); + } + + private void handleHome() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); + } + + private void sendDownAndUpKeyEvents(int keyCode) { + final long downTime = SystemClock.uptimeMillis(); + sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime); + sendKeyEventIdentityCleared( + keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis()); + } + + private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) { + KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, + InputDevice.SOURCE_KEYBOARD, null); + InputManager.getInstance() + .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + event.recycle(); + } + + private void handleRecents() { + mRecents.toggleRecentApps(); + } + + private void handleNotifications() { + mStatusBar.animateExpandNotificationsPanel(); + } + + private void handleQuickSettings() { + mStatusBar.animateExpandSettingsPanel(null); + } + + private void handlePowerDialog() { + IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); + + try { + windowManager.showGlobalActions(); + } catch (RemoteException e) { + Log.e(TAG, "failed to display power dialog."); + } + } + + private void handleToggleSplitScreen() { + mStatusBar.toggleSplitScreen(); + } + + private void handleLockScreen() { + IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); + + mContext.getSystemService(PowerManager.class).goToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY, 0); + try { + windowManager.lockNow(null); + } catch (RemoteException e) { + Log.e(TAG, "failed to lock screen."); + } + } + + private void handleTakeScreenshot() { + ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext); + screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + true, true, new Handler(Looper.getMainLooper()), null); + } + + private void handleAccessibilityMenu() { + AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked( + Display.DEFAULT_DISPLAY); + } + + private class SystemActionsBroadcastReceiver extends BroadcastReceiver { + private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK"; + private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME"; + private static final String INTENT_ACTION_RECENTS = "SYSTEM_ACTION_RECENTS"; + private static final String INTENT_ACTION_NOTIFICATIONS = "SYSTEM_ACTION_NOTIFICATIONS"; + private static final String INTENT_ACTION_QUICK_SETTINGS = "SYSTEM_ACTION_QUICK_SETTINGS"; + private static final String INTENT_ACTION_POWER_DIALOG = "SYSTEM_ACTION_POWER_DIALOG"; + private static final String INTENT_ACTION_TOGGLE_SPLIT_SCREEN = + "SYSTEM_ACTION_TOGGLE_SPLIT_SCREEN"; + private static final String INTENT_ACTION_LOCK_SCREEN = "SYSTEM_ACTION_LOCK_SCREEN"; + private static final String INTENT_ACTION_TAKE_SCREENSHOT = "SYSTEM_ACTION_TAKE_SCREENSHOT"; + private static final String INTENT_ACTION_ACCESSIBILITY_MENU = + "SYSTEM_ACTION_ACCESSIBILITY_MENU"; + + private PendingIntent createPendingIntent(Context context, String intentAction) { + switch (intentAction) { + case INTENT_ACTION_BACK: + case INTENT_ACTION_HOME: + case INTENT_ACTION_RECENTS: + case INTENT_ACTION_NOTIFICATIONS: + case INTENT_ACTION_QUICK_SETTINGS: + case INTENT_ACTION_POWER_DIALOG: + case INTENT_ACTION_TOGGLE_SPLIT_SCREEN: + case INTENT_ACTION_LOCK_SCREEN: + case INTENT_ACTION_TAKE_SCREENSHOT: + case INTENT_ACTION_ACCESSIBILITY_MENU: { + Intent intent = new Intent(intentAction); + return PendingIntent.getBroadcast(context, 0, intent, 0); + } + default: + break; + } + return null; + } + + private IntentFilter createIntentFilter() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(INTENT_ACTION_BACK); + intentFilter.addAction(INTENT_ACTION_HOME); + intentFilter.addAction(INTENT_ACTION_RECENTS); + intentFilter.addAction(INTENT_ACTION_NOTIFICATIONS); + intentFilter.addAction(INTENT_ACTION_QUICK_SETTINGS); + intentFilter.addAction(INTENT_ACTION_POWER_DIALOG); + intentFilter.addAction(INTENT_ACTION_TOGGLE_SPLIT_SCREEN); + intentFilter.addAction(INTENT_ACTION_LOCK_SCREEN); + intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT); + intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_MENU); + return intentFilter; + } + + @Override + public void onReceive(Context context, Intent intent) { + String intentAction = intent.getAction(); + switch (intentAction) { + case INTENT_ACTION_BACK: { + handleBack(); + break; + } + case INTENT_ACTION_HOME: { + handleHome(); + break; + } + case INTENT_ACTION_RECENTS: { + handleRecents(); + break; + } + case INTENT_ACTION_NOTIFICATIONS: { + handleNotifications(); + break; + } + case INTENT_ACTION_QUICK_SETTINGS: { + handleQuickSettings(); + break; + } + case INTENT_ACTION_POWER_DIALOG: { + handlePowerDialog(); + break; + } + case INTENT_ACTION_TOGGLE_SPLIT_SCREEN: { + handleToggleSplitScreen(); + break; + } + case INTENT_ACTION_LOCK_SCREEN: { + handleLockScreen(); + break; + } + case INTENT_ACTION_TAKE_SCREENSHOT: { + handleTakeScreenshot(); + break; + } + case INTENT_ACTION_ACCESSIBILITY_MENU: { + handleAccessibilityMenu(); + break; + } + default: + break; + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt new file mode 100644 index 000000000000..81b5f3698567 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -0,0 +1,400 @@ +/* + * 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.content.Context +import android.graphics.drawable.ClipDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.Icon +import android.graphics.drawable.LayerDrawable +import android.service.controls.Control +import android.service.controls.DeviceTypes +import android.service.controls.actions.BooleanAction +import android.service.controls.actions.ControlAction +import android.service.controls.actions.FloatAction +import android.service.controls.templates.ControlTemplate +import android.service.controls.templates.RangeTemplate +import android.service.controls.templates.ToggleRangeTemplate +import android.service.controls.templates.ToggleTemplate +import android.util.TypedValue +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView + +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.R + +private const val MIN_LEVEL = 0 +private const val MAX_LEVEL = 10000 + +class ControlViewHolder( + val layout: ViewGroup, + val controlsController: ControlsController +) { + val icon: ImageView = layout.requireViewById(R.id.icon) + val status: TextView = layout.requireViewById(R.id.status) + val statusExtra: TextView = layout.requireViewById(R.id.status_extra) + val title: TextView = layout.requireViewById(R.id.title) + val subtitle: TextView = layout.requireViewById(R.id.subtitle) + val context: Context = layout.getContext() + val clipLayer: ClipDrawable + val gd: GradientDrawable + lateinit var cws: ControlWithState + + init { + val ld = layout.getBackground() as LayerDrawable + ld.mutate() + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable + gd = clipLayer.getDrawable() as GradientDrawable + } + + fun bindData(cws: ControlWithState) { + this.cws = cws + + val (status, template) = cws.control?.let { + title.setText(it.getTitle()) + subtitle.setText(it.getSubtitle()) + Pair(it.getStatus(), it.getControlTemplate()) + } ?: run { + title.setText(cws.ci.controlTitle) + subtitle.setText("") + Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE) + } + + findBehavior(status, template).apply(this, cws) + } + + fun action(action: ControlAction) { + controlsController.action(cws.ci, action) + } + + private fun findBehavior(status: Int, template: ControlTemplate): Behavior { + return when { + status == Control.STATUS_UNKNOWN -> UnknownBehavior() + template is ToggleTemplate -> ToggleTemplateBehavior() + template is ToggleRangeTemplate -> ToggleRangeTemplateBehavior() + else -> { + object : Behavior { + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + cvh.status.setText(cws.control?.getStatusText()) + cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) + } + } + } + } + } + + internal fun applyRenderInfo(ri: RenderInfo) { + val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) + val bg = context.getResources().getColorStateList(ri.background, context.getTheme()) + status.setTextColor(fg) + statusExtra.setTextColor(fg) + + icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId)) + icon.setImageTintList(fg) + + gd.setColor(bg) + } + + fun setEnabled(enabled: Boolean) { + status.setEnabled(enabled) + icon.setEnabled(enabled) + } +} + +private interface Behavior { + fun apply(cvh: ControlViewHolder, cws: ControlWithState) + + fun findRenderInfo(deviceType: Int, isActive: Boolean): RenderInfo = + deviceRenderMap.getOrDefault(deviceType, unknownDeviceMap).getValue(isActive) +} + +private class UnknownBehavior : Behavior { + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + cvh.status.setText("Loading...") + cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) + } +} + +private class ToggleRangeTemplateBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleRangeTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var rangeTemplate: RangeTemplate + lateinit var statusExtra: TextView + lateinit var status: TextView + lateinit var context: Context + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + + statusExtra = cvh.statusExtra + status = cvh.status + + status.setText(control.getStatusText()) + + context = status.getContext() + + cvh.layout.setOnTouchListener(ToggleRangeTouchListener()) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleRangeTemplate + rangeTemplate = template.getRange() + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + updateRange((rangeTemplate.getCurrentValue() / 100.0f), checked) + + cvh.setEnabled(checked) + cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } + + fun beginUpdateRange() { + status.setVisibility(View.GONE) + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) + } + + fun updateRange(f: Float, checked: Boolean) { + clipLayer.setLevel(if (checked) (MAX_LEVEL * f).toInt() else MIN_LEVEL) + + if (checked && f < 100.0f && f > 0.0f) { + statusExtra.setText("" + (f * 100.0).toInt() + "%") + statusExtra.setVisibility(View.VISIBLE) + } else { + statusExtra.setText("") + statusExtra.setVisibility(View.GONE) + } + } + + fun endUpdateRange(f: Float) { + statusExtra.setText(" - " + (f * 100.0).toInt() + "%") + + val newValue = rangeTemplate.getMinValue() + + (f * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())) + + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_normal).toFloat()) + status.setVisibility(View.VISIBLE) + + cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(newValue))) + } + + fun findNearestStep(value: Float): Float { + var minDiff = 1000f + + var f = rangeTemplate.getMinValue() + while (f <= rangeTemplate.getMaxValue()) { + val currentDiff = Math.abs(value - f) + if (currentDiff < minDiff) { + minDiff = currentDiff + } else { + return f - rangeTemplate.getStepValue() + } + + f += rangeTemplate.getStepValue() + } + + return rangeTemplate.getMaxValue() + } + + inner class ToggleRangeTouchListener() : View.OnTouchListener { + private var initialTouchX: Float = 0.0f + private var initialTouchY: Float = 0.0f + private var isDragging: Boolean = false + private val minDragDiff = 20 + + override fun onTouch(v: View, e: MotionEvent): Boolean { + when (e.getActionMasked()) { + MotionEvent.ACTION_DOWN -> setupTouch(e) + MotionEvent.ACTION_MOVE -> detectDrag(v, e) + MotionEvent.ACTION_UP -> endTouch(v, e) + } + + return true + } + + private fun setupTouch(e: MotionEvent) { + initialTouchX = e.getX() + initialTouchY = e.getY() + } + + private fun detectDrag(v: View, e: MotionEvent) { + val xDiff = Math.abs(e.getX() - initialTouchX) + val yDiff = Math.abs(e.getY() - initialTouchY) + + if (xDiff < minDragDiff) { + isDragging = false + } else { + if (!isDragging) { + this@ToggleRangeTemplateBehavior.beginUpdateRange() + } + v.getParent().requestDisallowInterceptTouchEvent(true) + isDragging = true + if (yDiff > xDiff) { + endTouch(v, e) + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeTemplateBehavior.updateRange(percent, true) + } + } + } + + private fun endTouch(v: View, e: MotionEvent) { + if (!isDragging) { + this@ToggleRangeTemplateBehavior.toggle() + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeTemplateBehavior.endUpdateRange(percent) + } + + initialTouchX = 0.0f + initialTouchY = 0.0f + isDragging = false + } + } +} + +private class ToggleTemplateBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var context: Context + lateinit var status: TextView + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + status = cvh.status + + status.setText(control.getStatusText()) + + cvh.layout.setOnClickListener(View.OnClickListener() { toggle() }) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleTemplate + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL) + cvh.setEnabled(checked) + cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } +} + +internal data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) + +private val unknownDeviceMap = mapOf( + false to RenderInfo( + R.drawable.ic_light_off_gm2_24px, + R.color.unknown_foreground, + R.color.unknown_foreground), + true to RenderInfo( + R.drawable.ic_lightbulb_outline_gm2_24px, + R.color.unknown_foreground, + R.color.unknown_foreground) +) + +private val deviceRenderMap = mapOf<Int, Map<Boolean, RenderInfo>>( + DeviceTypes.TYPE_UNKNOWN to unknownDeviceMap, + DeviceTypes.TYPE_LIGHT to mapOf( + false to RenderInfo( + R.drawable.ic_light_off_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_lightbulb_outline_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_THERMOSTAT to mapOf( + false to RenderInfo( + R.drawable.ic_device_thermostat_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_device_thermostat_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_CAMERA to mapOf( + false to RenderInfo( + R.drawable.ic_videocam_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_videocam_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_LOCK to mapOf( + false to RenderInfo( + R.drawable.ic_lock_open_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_lock_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ), + DeviceTypes.TYPE_SWITCH to mapOf( + false to RenderInfo( + R.drawable.ic_switches_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_switches_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ), + DeviceTypes.TYPE_OUTLET to mapOf( + false to RenderInfo( + R.drawable.ic_power_off_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_power_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ) +) diff --git a/telephony/java/android/telephony/ims/RcsMessageStoreException.java b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt index 3b3fcf21dd7a..816f0b2cb1d1 100644 --- a/telephony/java/android/telephony/ims/RcsMessageStoreException.java +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 The Android Open Source Project + * 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. @@ -14,22 +14,18 @@ * limitations under the License. */ -package android.telephony.ims; +package com.android.systemui.controls.ui + +import android.service.controls.Control + +import com.android.systemui.controls.controller.ControlInfo /** - * An exception that happened on {@link RcsMessageStore} or one of the derived storage classes in - * {@link android.telephony.ims} - * - * @hide + * A container for: + * <ul> + * <li>ControlInfo - Basic cached info about a Control + * <li>Control - Actual Control parcelable received directly from + * the participating application + * </ul> */ -public class RcsMessageStoreException extends Exception { - - /** - * Constructs an {@link RcsMessageStoreException} with the specified detail message. - * @param message The detail message - * @see Throwable#getMessage() - */ - public RcsMessageStoreException(String message) { - super(message); - } -} +data class ControlWithState(val ci: ControlInfo, val control: Control?) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 0270c2b6b1b3..b07a75d5e757 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -19,12 +19,15 @@ package com.android.systemui.controls.ui import android.content.ComponentName import android.service.controls.Control import android.service.controls.actions.ControlAction +import android.view.ViewGroup interface ControlsUiController { + fun show(parent: ViewGroup) + fun hide() fun onRefreshState(componentName: ComponentName, controls: List<Control>) fun onActionResponse( componentName: ComponentName, controlId: String, @ControlAction.ResponseResult response: Int ) -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 0ace1263b49b..926fb6e75594 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -16,19 +16,204 @@ package com.android.systemui.controls.ui +import android.accounts.Account +import android.accounts.AccountManager import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder import android.service.controls.Control +import android.service.controls.TokenProvider +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView + +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.controller.ControlInfo +import com.android.systemui.controls.management.ControlsProviderSelectorActivity +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.R + +import dagger.Lazy + +import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton +private const val TAG = "ControlsUi" + +// TEMP CODE for MOCK +private const val TOKEN = "https://www.googleapis.com/auth/assistant" +private const val SCOPE = "oauth2:" + TOKEN +private var tokenProviderConnection: TokenProviderConnection? = null +class TokenProviderConnection(val cc: ControlsController, val context: Context) + : ServiceConnection { + private var mTokenProvider: TokenProvider? = null + + override fun onServiceConnected(cName: ComponentName, binder: IBinder) { + Thread({ + Log.i(TAG, "TokenProviderConnection connected") + mTokenProvider = TokenProvider.Stub.asInterface(binder) + + val mLastAccountName = mTokenProvider?.getAccountName() + + if (mLastAccountName == null || mLastAccountName.isEmpty()) { + Log.e(TAG, "NO ACCOUNT IS SET. Open HomeMock app") + } else { + mTokenProvider?.setAuthToken(getAuthToken(mLastAccountName)) + cc.subscribeToFavorites() + } + }, "TokenProviderThread").start() + } + + override fun onServiceDisconnected(cName: ComponentName) { + mTokenProvider = null + } + + fun getAuthToken(accountName: String): String? { + val am = AccountManager.get(context) + val accounts = am.getAccountsByType("com.google") + if (accounts == null || accounts.size == 0) { + Log.w(TAG, "No com.google accounts found") + return null + } + + var account: Account? = null + for (a in accounts) { + if (a.name.equals(accountName)) { + account = a + break + } + } + + if (account == null) { + account = accounts[0] + } + + try { + return am.blockingGetAuthToken(account!!, SCOPE, true) + } catch (e: Throwable) { + Log.e(TAG, "Error getting auth token", e) + return null + } + } +} + @Singleton -class ControlsUiControllerImpl @Inject constructor() : ControlsUiController { +class ControlsUiControllerImpl @Inject constructor ( + val controlsController: Lazy<ControlsController>, + val context: Context, + @Main val uiExecutor: Executor +) : ControlsUiController { + + private lateinit var controlInfos: List<ControlInfo> + private val controlsById = mutableMapOf<Pair<ComponentName, String>, ControlWithState>() + private val controlViewsById = mutableMapOf<String, ControlViewHolder>() + private lateinit var parent: ViewGroup + + override fun show(parent: ViewGroup) { + Log.d(TAG, "show()") + + this.parent = parent + + controlInfos = controlsController.get().getFavoriteControls() + + controlInfos.map { + ControlWithState(it, null) + }.associateByTo(controlsById) { Pair(it.ci.component, it.ci.controlId) } + + if (controlInfos.isEmpty()) { + showInitialSetupView() + } else { + showControlsView() + } + + // Temp code to pass auth + tokenProviderConnection = TokenProviderConnection(controlsController.get(), context) + val serviceIntent = Intent() + serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock", + "com.android.systemui.home.mock.AuthService")) + context.bindService(serviceIntent, tokenProviderConnection!!, Context.BIND_AUTO_CREATE) + } + + private fun showInitialSetupView() { + val inflater = LayoutInflater.from(context) + inflater.inflate(R.layout.controls_no_favorites, parent, true) + + val textView = parent.requireViewById(R.id.controls_title) as TextView + textView.setOnClickListener { + val i = Intent() + i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(i) + } + } + + private fun showControlsView() { + val inflater = LayoutInflater.from(context) + inflater.inflate(R.layout.controls_with_favorites, parent, true) + + val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup + var lastRow: ViewGroup = createRow(inflater, listView) + controlInfos.forEach { + Log.d(TAG, "favorited control id: " + it.controlId) + if (lastRow.getChildCount() == 2) { + lastRow = createRow(inflater, listView) + } + val item = inflater.inflate( + R.layout.controls_base_item, lastRow, false) as ViewGroup + lastRow.addView(item) + val cvh = ControlViewHolder(item, controlsController.get()) + cvh.bindData(controlsById.get(Pair(it.component, it.controlId))!!) + controlViewsById.put(it.controlId, cvh) + } + + val moreImageView = parent.requireViewById(R.id.controls_more) as View + moreImageView.setOnClickListener { + val i = Intent() + i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(i) + } + } + + override fun hide() { + Log.d(TAG, "hide()") + controlsController.get().unsubscribe() + context.unbindService(tokenProviderConnection) + tokenProviderConnection = null + + parent.removeAllViews() + controlsById.clear() + controlViewsById.clear() + } override fun onRefreshState(componentName: ComponentName, controls: List<Control>) { - TODO("not implemented") + Log.d(TAG, "onRefreshState()") + controls.forEach { c -> + controlsById.get(Pair(componentName, c.getControlId()))?.let { + Log.d(TAG, "onRefreshState() for id: " + c.getControlId()) + val cws = ControlWithState(it.ci, c) + controlsById.put(Pair(componentName, c.getControlId()), cws) + + uiExecutor.execute { + controlViewsById.get(c.getControlId())?.bindData(cws) + } + } + } } override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) { + Log.d(TAG, "onActionResponse()") TODO("not implemented") } -}
\ No newline at end of file + + private fun createRow(inflater: LayoutInflater, parent: ViewGroup): ViewGroup { + val row = inflater.inflate(R.layout.controls_row, parent, false) as ViewGroup + parent.addView(row) + return row + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 99dd5e2356d6..5de88e17d320 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -21,6 +21,7 @@ import com.android.systemui.ScreenDecorations; import com.android.systemui.SizeCompatModeActivityController; import com.android.systemui.SliceBroadcastRelayHandler; import com.android.systemui.SystemUI; +import com.android.systemui.accessibility.SystemActions; import com.android.systemui.accessibility.WindowMagnification; import com.android.systemui.biometrics.AuthController; import com.android.systemui.globalactions.GlobalActionsComponent; @@ -36,6 +37,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarModule; import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; +import com.android.systemui.toast.ToastUI; import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.volume.VolumeUI; @@ -140,12 +142,24 @@ public abstract class SystemUIBinder { @ClassKey(StatusBar.class) public abstract SystemUI bindsStatusBar(StatusBar sysui); + /** Inject into SystemActions. */ + @Binds + @IntoMap + @ClassKey(SystemActions.class) + public abstract SystemUI bindSystemActions(SystemActions sysui); + /** Inject into ThemeOverlayController. */ @Binds @IntoMap @ClassKey(ThemeOverlayController.class) public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui); + /** Inject into ToastUI. */ + @Binds + @IntoMap + @ClassKey(ToastUI.class) + public abstract SystemUI bindToastUI(ToastUI service); + /** Inject into TvStatusBar. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 83f6d45465b3..80d776a59235 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -93,12 +93,13 @@ import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.BlurUtils; +import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -183,6 +184,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final IStatusBarService mStatusBarService; private final NotificationShadeWindowController mNotificationShadeWindowController; private GlobalActionsPanelPlugin mPanelPlugin; + private ControlsUiController mControlsUiController; /** * @param context everything needs a context :( @@ -200,7 +202,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, TelecomManager telecomManager, MetricsLogger metricsLogger, BlurUtils blurUtils, SysuiColorExtractor colorExtractor, IStatusBarService statusBarService, - NotificationShadeWindowController notificationShadeWindowController) { + NotificationShadeWindowController notificationShadeWindowController, + ControlsUiController controlsUiController) { mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -220,6 +223,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mSysuiColorExtractor = colorExtractor; mStatusBarService = statusBarService; mNotificationShadeWindowController = notificationShadeWindowController; + mControlsUiController = controlsUiController; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -455,9 +459,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mKeyguardManager.isDeviceLocked()) : null; + boolean showControls = !mKeyguardManager.isDeviceLocked() && isControlsEnabled(mContext); + ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController, mBlurUtils, mSysuiColorExtractor, mStatusBarService, - mNotificationShadeWindowController, isControlsEnabled(mContext)); + mNotificationShadeWindowController, + showControls ? mControlsUiController : null); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -1543,13 +1550,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mHadTopUi; private final NotificationShadeWindowController mNotificationShadeWindowController; private final BlurUtils mBlurUtils; - private final boolean mControlsEnabled; + + private ControlsUiController mControlsUiController; + private ViewGroup mControlsView; ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils, SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, NotificationShadeWindowController notificationShadeWindowController, - boolean controlsEnabled) { + ControlsUiController controlsUiController) { super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions); mContext = context; mAdapter = adapter; @@ -1557,7 +1566,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mColorExtractor = sysuiColorExtractor; mStatusBarService = statusBarService; mNotificationShadeWindowController = notificationShadeWindowController; - mControlsEnabled = controlsEnabled; + mControlsUiController = controlsUiController; // Window initialization Window window = getWindow(); @@ -1639,6 +1648,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private void initializeLayout() { setContentView(getGlobalActionsLayoutId(mContext)); fixNavBarClipping(); + mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls); mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss()); @@ -1674,7 +1684,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private int getGlobalActionsLayoutId(Context context) { - if (mControlsEnabled) { + if (mControlsUiController != null) { return com.android.systemui.R.layout.global_actions_grid_v2; } @@ -1758,6 +1768,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mBlurUtils.radiusForRatio(animatedValue)); }) .start(); + if (mControlsUiController != null) { + mControlsUiController.show(mControlsView); + } } @Override @@ -1766,6 +1779,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } mShowing = false; + if (mControlsUiController != null) mControlsUiController.hide(); mGlobalActionsLayout.setTranslationX(0); mGlobalActionsLayout.setTranslationY(0); mGlobalActionsLayout.setAlpha(1); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 2fc7a9cf2434..14eec59211bd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -18,6 +18,7 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -53,6 +54,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -371,6 +373,7 @@ public class KeyguardViewMediator extends SystemUI { private boolean mPulsing; private boolean mLockLater; + private boolean mShowHomeOverLockscreen; private boolean mWakeAndUnlocking; private IKeyguardDrawnCallback mDrawnCallback; @@ -703,6 +706,20 @@ public class KeyguardViewMediator extends SystemUI { mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy; mDismissCallbackRegistry = dismissCallbackRegistry; mUiBgExecutor = uiBgExecutor; + mShowHomeOverLockscreen = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, + /* defaultValue = */ true); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) { + mShowHomeOverLockscreen = properties.getBoolean( + NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */); + } + } + }); } public void userActivity() { @@ -1972,7 +1989,10 @@ public class KeyguardViewMediator extends SystemUI { // windows that appear on top, ever int flags = StatusBarManager.DISABLE_NONE; if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) { - flags |= StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT; + if (!mShowHomeOverLockscreen) { + flags |= StatusBarManager.DISABLE_HOME; + } + flags |= StatusBarManager.DISABLE_RECENT; } if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 7c0f4f942bce..3af3701dff97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -25,6 +25,8 @@ import static android.view.Display.INVALID_DISPLAY; import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; import android.app.StatusBarManager; import android.app.StatusBarManager.Disable2Flags; import android.app.StatusBarManager.DisableFlags; @@ -119,6 +121,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_TOP_APP_WINDOW_CHANGED = 50 << MSG_SHIFT; private static final int MSG_SHOW_INATTENTIVE_SLEEP_WARNING = 51 << MSG_SHIFT; private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 52 << MSG_SHIFT; + private static final int MSG_SHOW_TOAST = 53 << MSG_SHIFT; + private static final int MSG_HIDE_TOAST = 54 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -308,6 +312,19 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * due to prolonged user inactivity should be dismissed. */ default void dismissInattentiveSleepWarning(boolean animated) { } + + /** + * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int, + * ITransientNotificationCallback) + */ + default void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback callback) { } + + /** + * @see IStatusBar#hideToast(String, IBinder) (String, IBinder) + */ + default void hideToast(String packageName, IBinder token) { } } public CommandQueue(Context context) { @@ -761,6 +778,31 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } @Override + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = packageName; + args.arg2 = token; + args.arg3 = text; + args.arg4 = windowToken; + args.arg5 = callback; + args.argi1 = duration; + mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget(); + } + } + + @Override + public void hideToast(String packageName, IBinder token) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = packageName; + args.arg2 = token; + mHandler.obtainMessage(MSG_HIDE_TOAST, args).sendToTarget(); + } + } + + @Override public void onBiometricAuthenticated() { synchronized (mLock) { mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget(); @@ -1178,6 +1220,30 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).dismissInattentiveSleepWarning((Boolean) msg.obj); } break; + case MSG_SHOW_TOAST: { + args = (SomeArgs) msg.obj; + String packageName = (String) args.arg1; + IBinder token = (IBinder) args.arg2; + CharSequence text = (CharSequence) args.arg3; + IBinder windowToken = (IBinder) args.arg4; + ITransientNotificationCallback callback = + (ITransientNotificationCallback) args.arg5; + int duration = args.argi1; + for (Callbacks callbacks : mCallbacks) { + callbacks.showToast(packageName, token, text, windowToken, duration, + callback); + } + break; + } + case MSG_HIDE_TOAST: { + args = (SomeArgs) msg.obj; + String packageName = (String) args.arg1; + IBinder token = (IBinder) args.arg2; + for (Callbacks callbacks : mCallbacks) { + callbacks.hideToast(packageName, token); + } + break; + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 3e3ef0ccb8ce..9e64748f2e65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -302,14 +302,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mForceNavBarHandleOpaque = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_FORCE_OPAQUE, - /* defaultValue = */ false); + /* defaultValue = */ true); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) { mForceNavBarHandleOpaque = properties.getBoolean( - NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ false); + NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true); } } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java index d6336ed3e18a..826af669cb39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java @@ -387,7 +387,7 @@ public class NavigationModeController implements Dumpable { Log.d(TAG, "setModeOverlay: overlayPackage=" + overlayPkg + " userId=" + userId); } - } catch (RemoteException e) { + } catch (SecurityException | IllegalStateException | RemoteException e) { Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index d06164963f7b..5a7c5c9b5ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -56,6 +56,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { private static final int MAX_DOTS = 1; private int mDotPadding; + private int mIconSpacing; private int mStaticDotDiameter; private int mUnderflowWidth; private int mUnderflowStart = 0; @@ -99,6 +100,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { mIconDotFrameWidth = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); + mIconSpacing = getResources().getDimensionPixelSize(R.dimen.status_bar_system_icon_spacing); int radius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); mStaticDotDiameter = 2 * radius; mUnderflowWidth = mIconDotFrameWidth + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding); @@ -163,20 +165,21 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { // Measure all children so that they report the correct width int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); mNeedsUnderflow = mShouldRestrictIcons && visibleCount > MAX_ICONS; - for (int i = 0; i < mMeasureViews.size(); i++) { + for (int i = 0; i < visibleCount; i++) { // Walking backwards View child = mMeasureViews.get(visibleCount - i - 1); measureChild(child, childWidthSpec, heightMeasureSpec); + int spacing = i == visibleCount - 1 ? 0 : mIconSpacing; if (mShouldRestrictIcons) { if (i < maxVisible && trackWidth) { - totalWidth += getViewTotalMeasuredWidth(child); + totalWidth += getViewTotalMeasuredWidth(child) + spacing; } else if (trackWidth) { // We've hit the icon limit; add space for dots totalWidth += mUnderflowWidth; trackWidth = false; } } else { - totalWidth += getViewTotalMeasuredWidth(child); + totalWidth += getViewTotalMeasuredWidth(child) + spacing; } } @@ -284,11 +287,15 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { continue; } + // Move translationX to the spot within StatusIconContainer's layout to add the view + // without cutting off the child view. + translationX -= getViewTotalWidth(child); childState.visibleState = STATE_ICON; - childState.xTranslation = translationX - getViewTotalWidth(child); + childState.xTranslation = translationX; mLayoutStates.add(0, childState); - translationX -= getViewTotalWidth(child); + // Shift translationX over by mIconSpacing for the next view. + translationX -= mIconSpacing; } // Show either 1-MAX_ICONS icons, or (MAX_ICONS - 1) icons + overflow @@ -306,7 +313,8 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { firstUnderflowIndex = i; break; } - mUnderflowStart = (int) Math.max(contentStart, state.xTranslation - mUnderflowWidth); + mUnderflowStart = (int) Math.max( + contentStart, state.xTranslation - mUnderflowWidth - mIconSpacing); visible++; } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java index 41e026af7c72..665cb6307b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java @@ -178,7 +178,7 @@ class ThemeOverlayManager { } else { mOverlayManager.setEnabled(pkg, false, userHandle); } - } catch (IllegalStateException e) { + } catch (SecurityException | IllegalStateException e) { Log.e(TAG, String.format("setEnabled failed: %s %s %b", pkg, userHandle, enabled), e); } diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java new file mode 100644 index 000000000000..dea8c5d49dfc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -0,0 +1,212 @@ +/* + * 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.toast; + +import android.annotation.MainThread; +import android.annotation.Nullable; +import android.app.INotificationManager; +import android.app.ITransientNotificationCallback; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.internal.R; +import com.android.systemui.SystemUI; +import com.android.systemui.statusbar.CommandQueue; + +import java.util.Objects; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Controls display of text toasts. + */ +@Singleton +public class ToastUI extends SystemUI implements CommandQueue.Callbacks { + private static final String TAG = "ToastUI"; + + /** + * Values taken from {@link Toast}. + */ + private static final long DURATION_SHORT = 4000; + private static final long DURATION_LONG = 7000; + + private final CommandQueue mCommandQueue; + private final WindowManager mWindowManager; + private final INotificationManager mNotificationManager; + private final AccessibilityManager mAccessibilityManager; + private ToastEntry mCurrentToast; + + @Inject + public ToastUI(Context context, CommandQueue commandQueue) { + super(context); + mCommandQueue = commandQueue; + mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mNotificationManager = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + mAccessibilityManager = AccessibilityManager.getInstance(context); + } + + @Override + public void start() { + mCommandQueue.addCallback(this); + } + + @Override + @MainThread + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { + if (mCurrentToast != null) { + hideCurrentToast(); + } + View view = getView(text); + LayoutParams params = getLayoutParams(windowToken, duration); + mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback); + try { + mWindowManager.addView(view, params); + } catch (WindowManager.BadTokenException e) { + Log.w(TAG, "Error while attempting to show toast from " + packageName, e); + return; + } + trySendAccessibilityEvent(view, packageName); + if (callback != null) { + try { + callback.onToastShown(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling back " + packageName + " to notify onToastShow()", e); + } + } + } + + @Override + @MainThread + public void hideToast(String packageName, IBinder token) { + if (mCurrentToast == null || !Objects.equals(mCurrentToast.packageName, packageName) + || !Objects.equals(mCurrentToast.token, token)) { + Log.w(TAG, "Attempt to hide non-current toast from package " + packageName); + return; + } + hideCurrentToast(); + } + + @MainThread + private void hideCurrentToast() { + if (mCurrentToast.view.getParent() != null) { + mWindowManager.removeViewImmediate(mCurrentToast.view); + } + String packageName = mCurrentToast.packageName; + try { + mNotificationManager.finishToken(packageName, mCurrentToast.windowToken); + } catch (RemoteException e) { + Log.w(TAG, "Error finishing toast window token from package " + packageName, e); + } + if (mCurrentToast.callback != null) { + try { + mCurrentToast.callback.onToastHidden(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling back " + packageName + " to notify onToastHide()", e); + } + } + mCurrentToast = null; + } + + private void trySendAccessibilityEvent(View view, String packageName) { + if (!mAccessibilityManager.isEnabled()) { + return; + } + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); + event.setClassName(Toast.class.getName()); + event.setPackageName(packageName); + view.dispatchPopulateAccessibilityEvent(event); + mAccessibilityManager.sendAccessibilityEvent(event); + } + + private View getView(CharSequence text) { + View view = LayoutInflater.from(mContext).inflate( + R.layout.transient_notification, null); + TextView textView = view.findViewById(com.android.internal.R.id.message); + textView.setText(text); + return view; + } + + private LayoutParams getLayoutParams(IBinder windowToken, int duration) { + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + params.format = PixelFormat.TRANSLUCENT; + params.windowAnimations = com.android.internal.R.style.Animation_Toast; + params.type = WindowManager.LayoutParams.TYPE_TOAST; + params.setTitle("Toast"); + params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + Configuration config = mContext.getResources().getConfiguration(); + int specificGravity = mContext.getResources().getInteger( + com.android.internal.R.integer.config_toastDefaultGravity); + int gravity = Gravity.getAbsoluteGravity(specificGravity, config.getLayoutDirection()); + params.gravity = gravity; + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { + params.horizontalWeight = 1.0f; + } + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { + params.verticalWeight = 1.0f; + } + params.x = 0; + params.y = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); + params.verticalMargin = 0; + params.horizontalMargin = 0; + params.packageName = mContext.getPackageName(); + params.hideTimeoutMilliseconds = + (duration == Toast.LENGTH_LONG) ? DURATION_LONG : DURATION_SHORT; + params.token = windowToken; + return params; + } + + private static class ToastEntry { + public final String packageName; + public final IBinder token; + public final View view; + public final IBinder windowToken; + + @Nullable + public final ITransientNotificationCallback callback; + + private ToastEntry(String packageName, IBinder token, View view, IBinder windowToken, + @Nullable ITransientNotificationCallback callback) { + this.packageName = packageName; + this.token = token; + this.view = view; + this.windowToken = windowToken; + this.callback = callback; + } + } +} diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml index 5c35c51dc77f..4aae3cc3000d 100644 --- a/packages/Tethering/apex/AndroidManifest.xml +++ b/packages/Tethering/apex/AndroidManifest.xml @@ -20,8 +20,10 @@ <application android:hasCode="false" /> <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version before ship. --> - <uses-sdk + <!-- TODO: Uncomment this when the R API level is fixed. b/148281152 --> + <!--uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> + --> </manifest> diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 79c693040416..37ce1d57da36 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -136,6 +136,12 @@ public class TetheringManager { */ public static final int TETHERING_NCM = 4; + /** + * Ethernet tethering type. + * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback) + */ + public static final int TETHERING_ETHERNET = 5; + public static final int TETHER_ERROR_NO_ERROR = 0; public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 57cc4dd554f1..190d25098644 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -93,6 +93,8 @@ public class IpServer extends StateMachine { private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1"; private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24; + private static final String ETHERNET_IFACE_ADDR = "192.168.50.1"; + private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24; // TODO: have PanService use some visible version of this constant private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; @@ -426,6 +428,10 @@ public class IpServer extends StateMachine { } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR); prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; + } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) { + // TODO: randomize address for tethering too, similarly to wifi + srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR); + prefixLen = ETHERNET_IFACE_PREFIX_LENGTH; } else { // BT configures the interface elsewhere: only start DHCP. // TODO: make all tethering types behave the same way, and delete the bluetooth diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 02ba17e4b48b..07abe1adeb52 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -30,6 +30,7 @@ import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; import static android.net.TetheringManager.EXTRA_ERRORED_TETHER; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; @@ -68,6 +69,7 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; +import android.net.EthernetManager; import android.net.IIntResultListener; import android.net.INetd; import android.net.ITetheringEventCallback; @@ -112,6 +114,7 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; @@ -214,6 +217,13 @@ public class Tethering { private boolean mDataSaverEnabled = false; private String mWifiP2pTetherInterface = null; + @GuardedBy("mPublicSync") + private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest; + @GuardedBy("mPublicSync") + private String mConfiguredEthernetIface; + @GuardedBy("mPublicSync") + private EthernetCallback mEthernetCallback; + public Tethering(TetheringDependencies deps) { mLog.mark("Tethering.constructed"); mDeps = deps; @@ -464,6 +474,10 @@ public class Tethering { result = setNcmTethering(enable); sendTetherResult(listener, result); break; + case TETHERING_ETHERNET: + result = setEthernetTethering(enable); + sendTetherResult(listener, result); + break; default: Log.w(TAG, "Invalid tether type."); sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE); @@ -540,6 +554,57 @@ public class Tethering { }, BluetoothProfile.PAN); } + private int setEthernetTethering(final boolean enable) { + final EthernetManager em = (EthernetManager) mContext.getSystemService( + Context.ETHERNET_SERVICE); + synchronized (mPublicSync) { + if (enable) { + mEthernetCallback = new EthernetCallback(); + mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback); + } else { + if (mConfiguredEthernetIface != null) { + stopEthernetTetheringLocked(); + mEthernetIfaceRequest.release(); + } + mEthernetCallback = null; + } + } + return TETHER_ERROR_NO_ERROR; + } + + private void stopEthernetTetheringLocked() { + if (mConfiguredEthernetIface == null) return; + changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE); + stopTrackingInterfaceLocked(mConfiguredEthernetIface); + mConfiguredEthernetIface = null; + } + + private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback { + @Override + public void onAvailable(String iface) { + synchronized (mPublicSync) { + if (this != mEthernetCallback) { + // Ethernet callback arrived after Ethernet tethering stopped. Ignore. + return; + } + maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET); + changeInterfaceState(iface, IpServer.STATE_TETHERED); + mConfiguredEthernetIface = iface; + } + } + + @Override + public void onUnavailable() { + synchronized (mPublicSync) { + if (this != mEthernetCallback) { + // onAvailable called after stopping Ethernet tethering. + return; + } + stopEthernetTetheringLocked(); + } + } + } + int tether(String iface) { return tether(iface, IpServer.STATE_TETHERED); } @@ -590,6 +655,7 @@ public class Tethering { stopTethering(TETHERING_WIFI_P2P); stopTethering(TETHERING_USB); stopTethering(TETHERING_BLUETOOTH); + stopTethering(TETHERING_ETHERNET); } int getLastTetherError(String iface) { diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 53782fed1c50..13174c5bb57a 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -19,6 +19,7 @@ android_test { certificate: "platform", srcs: [ "src/**/*.java", + "src/**/*.kt", ], test_suites: [ "device-tests", diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml index 0a1cdd35b10c..530bc0788a78 100644 --- a/packages/Tethering/tests/unit/AndroidManifest.xml +++ b/packages/Tethering/tests/unit/AndroidManifest.xml @@ -16,6 +16,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack.tethering.tests.unit"> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/> + <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> </application> diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto index 821db860dd96..789019ce8b75 100644 --- a/proto/src/task_snapshot.proto +++ b/proto/src/task_snapshot.proto @@ -34,4 +34,5 @@ string top_activity_component = 10; float scale = 11; int64 id = 12; + int32 rotation = 13; } diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 3e74b7a92f5d..a5877ccbde7c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -134,6 +134,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ boolean mRequestTouchExplorationMode; + private boolean mServiceHandlesDoubleTap; + + private boolean mRequestMultiFingerGestures; + boolean mRequestFilterKeyEvents; boolean mRetrieveInteractiveWindows; @@ -298,6 +302,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ mRequestTouchExplorationMode = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; + mServiceHandlesDoubleTap = (info.flags + & 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; mRetrieveInteractiveWindows = (info.flags @@ -1689,4 +1697,12 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ msg.sendToTarget(); } } + + public boolean isServiceHandlesDoubleTapEnabled() { + return mServiceHandlesDoubleTap; + } + + public boolean isMultiFingerGesturesEnabled() { + return mRequestMultiFingerGestures; + } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 49582a97b890..efddd8698f1b 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -99,9 +99,28 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER = 0x00000040; - static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS - | FLAG_FEATURE_AUTOCLICK | FLAG_FEATURE_TOUCH_EXPLORATION - | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; + /** + * Flag for dispatching double tap and double tap and hold to the service. + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x00000080; + +/** + * Flag for enabling multi-finger gestures. + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100; + + static final int FEATURES_AFFECTING_MOTION_EVENTS = + FLAG_FEATURE_INJECT_MOTION_EVENTS + | FLAG_FEATURE_AUTOCLICK + | FLAG_FEATURE_TOUCH_EXPLORATION + | FLAG_FEATURE_SCREEN_MAGNIFIER + | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER + | FLAG_SERVICE_HANDLES_DOUBLE_TAP + | FLAG_REQUEST_MULTI_FINGER_GESTURES; private final Context mContext; @@ -391,6 +410,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) { TouchExplorer explorer = new TouchExplorer(displayContext, mAms); + if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) { + explorer.setServiceHandlesDoubleTap(true); + } + if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { + explorer.setMultiFingerGesturesEnabled(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 bcaecea4c388..61e1adf2301c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1610,6 +1610,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isHandlingAccessibilityEventsLocked() && userState.isTouchExplorationEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; + if (userState.isServiceHandlesDoubleTapEnabledLocked()) { + flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP; + } + if (userState.isMultiFingerGesturesEnabledLocked()) { + flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; + } } if (userState.isFilterKeyEventsEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; @@ -1882,26 +1888,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void updateTouchExplorationLocked(AccessibilityUserState userState) { - boolean enabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); + boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); + boolean serviceHandlesDoubleTapEnabled = false; + boolean requestMultiFingerGestures = false; final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); if (canRequestAndRequestsTouchExplorationLocked(service, userState)) { - enabled = true; + touchExplorationEnabled = true; + serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); + requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); break; } } - if (enabled != userState.isTouchExplorationEnabledLocked()) { - userState.setTouchExplorationEnabledLocked(enabled); + if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) { + userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0, + Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0, userState.mUserId); } finally { Binder.restoreCallingIdentity(identity); } } + userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); + userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); } 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 ebe2af62b5db..4e7da97bab36 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -103,6 +103,8 @@ class AccessibilityUserState { private boolean mIsPerformGesturesEnabled; private boolean mIsTextHighContrastEnabled; private boolean mIsTouchExplorationEnabled; + private boolean mServiceHandlesDoubleTap; + private boolean mRequestMultiFingerGestures; private int mUserInteractiveUiTimeout; private int mUserNonInteractiveUiTimeout; private int mNonInteractiveUiTimeout = 0; @@ -151,6 +153,8 @@ class AccessibilityUserState { mAccessibilityShortcutKeyTargets.clear(); mAccessibilityButtonTargets.clear(); mIsTouchExplorationEnabled = false; + mServiceHandlesDoubleTap = false; + mRequestMultiFingerGestures = false; mIsDisplayMagnificationEnabled = false; mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; @@ -351,6 +355,8 @@ class AccessibilityUserState { // Touch exploration relies on enabled accessibility. if (a11yEnabled && mIsTouchExplorationEnabled) { clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP; + clientState |= AccessibilityManager.STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES; } if (mIsTextHighContrastEnabled) { clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED; @@ -431,6 +437,10 @@ class AccessibilityUserState { pw.println(); pw.append(" attributes:{id=").append(String.valueOf(mUserId)); pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled)); + pw.append(", serviceHandlesDoubleTap=") + .append(String.valueOf(mServiceHandlesDoubleTap)); + pw.append(", requestMultiFingerGestures=") + .append(String.valueOf(mRequestMultiFingerGestures)); pw.append(", displayMagnificationEnabled=").append(String.valueOf( mIsDisplayMagnificationEnabled)); pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled)); @@ -675,6 +685,22 @@ class AccessibilityUserState { mIsTouchExplorationEnabled = enabled; } + public boolean isServiceHandlesDoubleTapEnabledLocked() { + return mServiceHandlesDoubleTap; + } + + public void setServiceHandlesDoubleTapLocked(boolean enabled) { + mServiceHandlesDoubleTap = enabled; + } + + public boolean isMultiFingerGesturesEnabledLocked() { + return mRequestMultiFingerGestures; + } + + public void setMultiFingerGesturesLocked(boolean enabled) { + mRequestMultiFingerGestures = enabled; + } + public int getUserInteractiveUiTimeoutLocked() { return mUserInteractiveUiTimeout; } 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 50d21ba59996..b5660ae5d41a 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -65,6 +65,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener { private final Handler mHandler; // Listener to be notified of gesture start and end. private Listener mListener; + // Whether double tap and double tap and hold will be dispatched to the service or handled in + // the framework. + private boolean mServiceHandlesDoubleTap = false; + // Whether multi-finger gestures are enabled. + boolean mMultiFingerGesturesEnabled; + // A list of all the multi-finger gestures, for easy adding and removal. + private final List<GestureMatcher> mMultiFingerGestures = new ArrayList<>(); // Shared state information. private TouchState mState; @@ -154,18 +161,23 @@ class GestureManifold implements GestureMatcher.StateChangeListener { */ public interface Listener { /** - * Called when the user has performed a double tap and then held down the second tap. + * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap + * and hold is dispatched via onGestureCompleted. Otherwise, this method is called when the + * user has performed a double tap and then held down the second tap. */ void onDoubleTapAndHold(); /** - * Called when the user lifts their finger on the second tap of a double tap. + * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap is + * dispatched via onGestureCompleted. Otherwise, this method is called when the user lifts + * their finger on the second tap of a double tap. + * * @return true if the event is consumed, else false */ boolean onDoubleTap(); /** - * Called when the system has decided the event stream is a gesture. + * Called when the system has decided the event stream is a potential gesture. * * @return true if the event is consumed, else false */ @@ -193,7 +205,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener { public void onStateChanged( int gestureId, int state, MotionEvent event, MotionEvent rawEvent, int policyFlags) { if (state == GestureMatcher.STATE_GESTURE_STARTED && !mState.isGestureDetecting()) { - mListener.onGestureStarted(); + if (gestureId == GESTURE_DOUBLE_TAP || gestureId == GESTURE_DOUBLE_TAP_AND_HOLD) { + if (mServiceHandlesDoubleTap) { + mListener.onGestureStarted(); + } + } else { + mListener.onGestureStarted(); + } } else if (state == GestureMatcher.STATE_GESTURE_COMPLETED) { onGestureCompleted(gestureId); } else if (state == GestureMatcher.STATE_GESTURE_CANCELED && mState.isGestureDetecting()) { @@ -217,11 +235,23 @@ class GestureManifold implements GestureMatcher.StateChangeListener { // Gestures that complete on a delay call clear() here. switch (gestureId) { case GESTURE_DOUBLE_TAP: - mListener.onDoubleTap(); + if (mServiceHandlesDoubleTap) { + AccessibilityGestureEvent gestureEvent = + new AccessibilityGestureEvent(gestureId, event.getDisplayId()); + mListener.onGestureCompleted(gestureEvent); + } else { + mListener.onDoubleTap(); + } clear(); break; case GESTURE_DOUBLE_TAP_AND_HOLD: - mListener.onDoubleTapAndHold(); + if (mServiceHandlesDoubleTap) { + AccessibilityGestureEvent gestureEvent = + new AccessibilityGestureEvent(gestureId, event.getDisplayId()); + mListener.onGestureCompleted(gestureEvent); + } else { + mListener.onDoubleTapAndHold(); + } clear(); break; default: @@ -231,4 +261,27 @@ class GestureManifold implements GestureMatcher.StateChangeListener { break; } } + + public boolean isMultiFingerGesturesEnabled() { + return mMultiFingerGesturesEnabled; + } + + public void setMultiFingerGesturesEnabled(boolean mode) { + if (mMultiFingerGesturesEnabled != mode) { + mMultiFingerGesturesEnabled = mode; + if (mode) { + mGestures.addAll(mMultiFingerGestures); + } else { + mGestures.removeAll(mMultiFingerGestures); + } + } + } + + public void setServiceHandlesDoubleTap(boolean mode) { + mServiceHandlesDoubleTap = mode; + } + + public boolean isServiceHandlesDoubleTapEnabled() { + return mServiceHandlesDoubleTap; + } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java index 4c9e590592fe..386cb0636cc2 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java @@ -70,6 +70,13 @@ class MultiTap extends GestureMatcher { } mBaseX = event.getX(); mBaseY = event.getY(); + if (mCurrentTaps + 1 == mTargetTaps) { + // Start gesture detecting on down of final tap. + // Note that if this instance is matching double tap, + // and the service is not requesting to handle double tap, GestureManifold will + // ignore this. + startGesture(event, rawEvent, policyFlags); + } } @Override 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 ba890c5ee41d..2cc11c580d94 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -254,7 +254,10 @@ public class TouchExplorer extends BaseEventStreamTransformation } else if (mState.isDelegating()) { handleMotionEventStateDelegating(event, rawEvent, policyFlags); } else if (mState.isGestureDetecting()) { - // Already handled. + // Make sure we don't prematurely get TOUCH_INTERACTION_END + // It will be delivered on gesture completion or cancelation. + // Note that the delay for sending GESTURE_DETECTION_END remains in place. + mSendTouchInteractionEndDelayed.cancel(); } else { Slog.e(LOG_TAG, "Illegal state: " + mState); clear(event, policyFlags); @@ -331,12 +334,8 @@ public class TouchExplorer extends BaseEventStreamTransformation @Override public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) { - if (!mState.isGestureDetecting()) { - return false; - } - endGestureDetection(true); - + mSendTouchInteractionEndDelayed.cancel(); mAms.onGesture(gestureEvent); return true; @@ -516,6 +515,9 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; case 2: + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + return; + } // Make sure we don't have any pending transitions to touch exploration mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); @@ -538,6 +540,9 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; default: + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + return; + } // More than two pointers are delegated to the view hierarchy. mState.startDelegating(); event = MotionEvent.obtainNoHistory(event); @@ -583,6 +588,9 @@ public class TouchExplorer extends BaseEventStreamTransformation event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + return; + } if (mSendHoverEnterAndMoveDelayed.isPending()) { // We have not started sending events so cancel // scheduled sending events. @@ -610,6 +618,9 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; default: + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + return; + } // Three or more fingers is something other than touch exploration. if (mSendHoverEnterAndMoveDelayed.isPending()) { // We have not started sending events so cancel @@ -632,6 +643,10 @@ public class TouchExplorer extends BaseEventStreamTransformation */ private void handleMotionEventStateDragging( MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + // Multi-finger gestures conflict with this functionality. + return; + } int pointerIdBits = 0; // Clear the dragging pointer id if it's no longer valid. if (event.findPointerIndex(mDraggingPointerId) == -1) { @@ -742,6 +757,10 @@ public class TouchExplorer extends BaseEventStreamTransformation */ private void handleMotionEventStateDelegating( MotionEvent event, MotionEvent rawEvent, int policyFlags) { + if (mGestureDetector.isMultiFingerGesturesEnabled()) { + // Multi-finger gestures conflict with this functionality. + return; + } switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: { Slog.e(LOG_TAG, "Delegating state can only be reached if " @@ -875,6 +894,22 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** + * Whether to dispatch double tap and double tap and hold to the service rather than handle them + * in the framework. + */ + public void setServiceHandlesDoubleTap(boolean mode) { + mGestureDetector.setServiceHandlesDoubleTap(mode); + } + + /** + * This function turns on and off multi-finger gestures. When enabled, multi-finger gestures + * will disable delegating and dragging functionality. + */ + public void setMultiFingerGesturesEnabled(boolean enabled) { + mGestureDetector.setMultiFingerGesturesEnabled(enabled); + } + + /** * Class for delayed exiting from gesture detecting mode. */ private final class ExitGestureDetectionModeDelayed implements Runnable { diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java index f69b6387a605..b229e9f30180 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java @@ -44,6 +44,7 @@ public class AppWidgetService extends SystemService { public void onBootPhase(int phase) { if (phase == PHASE_ACTIVITY_MANAGER_READY) { mImpl.setSafeMode(isSafeMode()); + mImpl.systemServicesReady(); } } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 26245b15f92b..97f27caaad48 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -24,9 +24,11 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AppOpsManagerInternal; import android.app.IApplicationThread; import android.app.IServiceConnection; import android.app.KeyguardManager; @@ -232,6 +234,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private KeyguardManager mKeyguardManager; private DevicePolicyManagerInternal mDevicePolicyManagerInternal; private PackageManagerInternal mPackageManagerInternal; + private ActivityManagerInternal mActivityManagerInternal; + private AppOpsManagerInternal mAppOpsManagerInternal; private SecurityPolicy mSecurityPolicy; @@ -272,6 +276,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal()); } + void systemServicesReady() { + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); + mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class); + } + private void computeMaximumWidgetBitmapMemory() { WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); @@ -634,8 +643,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final SuspendDialogInfo dialogInfo = mPackageManagerInternal.getSuspendedDialogInfo(providerPackage, suspendingPackage, providerUserId); + // TODO(b/148035643): Send the original widget intent or ACTION_MAIN as an + // IntentSender to SuspendedAppActivity. onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent( - providerPackage, suspendingPackage, dialogInfo, null, providerUserId); + providerPackage, suspendingPackage, dialogInfo, null, null, + providerUserId); } } else if (provider.maskedByQuietProfile) { showBadge = true; @@ -867,6 +879,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku outUpdates.add(updatesMap.valueAt(j)); } } + updateAppOpsLocked(host, true); + // Reset the update counter once all the updates have been calculated host.lastWidgetUpdateSequenceNo = updateSequenceNo; return new ParceledListSlice<>(outUpdates); @@ -895,6 +909,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (host != null) { host.callbacks = null; pruneHostLocked(host); + updateAppOpsLocked(host, false); } } } @@ -1952,7 +1967,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked()); } } - private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) { if (viewId == ID_VIEWS_UPDATE || viewId == ID_PROVIDER_CHANGED) { // A view id should never collide with these constants but a developer can call this @@ -3618,6 +3632,26 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return false; } + private void updateAppOpsLocked(Host host, boolean visible) { + // The launcher must be at TOP. + final int procState = mActivityManagerInternal.getUidProcessState(host.id.uid); + if (procState > ActivityManager.PROCESS_STATE_TOP) { + return; + } + + final List<ResolveInfo> allHomeCandidates = new ArrayList<>(); + // Default launcher from package manager. + final ComponentName defaultLauncher = mPackageManagerInternal + .getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getUserId(host.id.uid)); + // The launcher must be default launcher. + if (defaultLauncher == null + || !defaultLauncher.getPackageName().equals(host.id.packageName)) { + return; + } + + mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUids(), visible); + } + private final class CallbackHandler extends Handler { public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1; public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2; @@ -4099,6 +4133,16 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku PendingHostUpdate.appWidgetRemoved(appWidgetId)); } + public SparseArray<String> getWidgetUids() { + final SparseArray<String> uids = new SparseArray<>(); + for (int i = widgets.size() - 1; i >= 0; i--) { + final Widget widget = widgets.get(i); + final ProviderId providerId = widget.provider.id; + uids.put(providerId.uid, providerId.componentName.getPackageName()); + } + return uids; + } + @Override public String toString() { return "Host{" + id + (zombie ? " Z" : "") + '}'; @@ -4853,6 +4897,5 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public void unlockUser(int userId) { handleUserUnlocked(userId); } - } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 8eca62a4932b..0b7029b1a71d 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -45,7 +45,12 @@ import android.database.ContentObserver; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; +import android.os.Looper; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; @@ -55,8 +60,11 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.service.contentcapture.ActivityEvent.ActivityEventType; +import android.service.contentcapture.IDataShareCallback; +import android.service.contentcapture.IDataShareReadAdapter; import android.util.ArraySet; import android.util.LocalLog; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -64,7 +72,10 @@ import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.ContentCaptureHelper; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; +import android.view.contentcapture.DataShareWriteAdapter; import android.view.contentcapture.IContentCaptureManager; +import android.view.contentcapture.IDataShareWriteAdapter; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AbstractRemoteService; @@ -77,9 +88,16 @@ import com.android.server.infra.AbstractMasterSystemService; import com.android.server.infra.FrameworkResourcesServiceNameResolver; import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; /** * A service used to observe the contents of the screen. @@ -91,9 +109,13 @@ import java.util.List; public final class ContentCaptureManagerService extends AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> { + private static final String TAG = ContentCaptureManagerService.class.getSimpleName(); static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes + private static final int MAX_DATA_SHARE_FILE_DESCRIPTORS_TTL_MS = 1_000 * 60 * 5; // 5 minutes + private static final int MAX_CONCURRENT_FILE_SHARING_REQUESTS = 10; + private static final int DATA_SHARE_BYTE_BUFFER_LENGTH = 1_024; private final LocalService mLocalService = new LocalService(); @@ -126,6 +148,12 @@ public final class ContentCaptureManagerService extends @GuardedBy("mLock") int mDevCfgLogHistorySize; @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs; + private final Executor mDataShareExecutor = Executors.newCachedThreadPool(); + private final Handler mHandler = new Handler(Looper.getMainLooper()); + + @GuardedBy("mLock") + private final Set<String> mPackagesWithShareRequests = new HashSet<>(); + final GlobalContentCaptureOptions mGlobalContentCaptureOptions = new GlobalContentCaptureOptions(); @@ -140,11 +168,11 @@ public final class ContentCaptureManagerService extends setDeviceConfigProperties(); if (mDevCfgLogHistorySize > 0) { - if (debug) Slog.d(mTag, "log history size: " + mDevCfgLogHistorySize); + if (debug) Slog.d(TAG, "log history size: " + mDevCfgLogHistorySize); mRequestsHistory = new LocalLog(mDevCfgLogHistorySize); } else { if (debug) { - Slog.d(mTag, "disabled log history because size is " + mDevCfgLogHistorySize); + Slog.d(TAG, "disabled log history because size is " + mDevCfgLogHistorySize); } mRequestsHistory = null; } @@ -155,7 +183,7 @@ public final class ContentCaptureManagerService extends final boolean disabled = !isEnabledBySettings(userId); // Sets which services are disabled by settings if (disabled) { - Slog.i(mTag, "user " + userId + " disabled by settings"); + Slog.i(TAG, "user " + userId + " disabled by settings"); if (mDisabledBySettings == null) { mDisabledBySettings = new SparseBooleanArray(1); } @@ -218,7 +246,7 @@ public final class ContentCaptureManagerService extends @Override // from AbstractMasterSystemService protected void enforceCallingPermissionForManagement() { - getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag); + getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, TAG); } @Override // from AbstractMasterSystemService @@ -242,7 +270,7 @@ public final class ContentCaptureManagerService extends isEnabledBySettings(userId)); return; default: - Slog.w(mTag, "Unexpected property (" + property + "); updating cache instead"); + Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); } } @@ -279,7 +307,7 @@ public final class ContentCaptureManagerService extends setFineTuneParamsFromDeviceConfig(); return; default: - Slog.i(mTag, "Ignoring change on " + key); + Slog.i(TAG, "Ignoring change on " + key); } } } @@ -306,7 +334,7 @@ public final class ContentCaptureManagerService extends ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT, (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS); if (verbose) { - Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): " + Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): " + "bufferSize=" + mDevCfgMaxBufferSize + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs @@ -325,7 +353,7 @@ public final class ContentCaptureManagerService extends verbose = ContentCaptureHelper.sVerbose; debug = ContentCaptureHelper.sDebug; if (verbose) { - Slog.v(mTag, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel + Slog.v(TAG, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel + ", debug=" + debug + ", verbose=" + verbose); } } @@ -340,7 +368,7 @@ public final class ContentCaptureManagerService extends private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) { if (verbose) { - Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled); + Slog.v(TAG, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled); } final List<UserInfo> users = getSupportedUsers(); @@ -355,17 +383,17 @@ public final class ContentCaptureManagerService extends synchronized (mLock) { if (mDisabledByDeviceConfig == newDisabledValue) { if (verbose) { - Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue); + Slog.v(TAG, "setDisabledByDeviceConfig(): already " + newDisabledValue); } return; } mDisabledByDeviceConfig = newDisabledValue; - Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig); + Slog.i(TAG, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig); for (int i = 0; i < users.size(); i++) { final int userId = users.get(i).id; boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId); - Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user " + Slog.i(TAG, "setDisabledByDeviceConfig(): updating service for user " + userId + " to " + (disabled ? "'disabled'" : "'enabled'")); updateCachedServiceLocked(userId, disabled); } @@ -381,16 +409,16 @@ public final class ContentCaptureManagerService extends final boolean alreadyEnabled = !mDisabledBySettings.get(userId); if (!(enabled ^ alreadyEnabled)) { if (debug) { - Slog.d(mTag, "setContentCaptureFeatureEnabledForUser(): already " + enabled); + Slog.d(TAG, "setContentCaptureFeatureEnabledForUser(): already " + enabled); } return; } if (enabled) { - Slog.i(mTag, "setContentCaptureFeatureEnabled(): enabling service for user " + Slog.i(TAG, "setContentCaptureFeatureEnabled(): enabling service for user " + userId); mDisabledBySettings.delete(userId); } else { - Slog.i(mTag, "setContentCaptureFeatureEnabled(): disabling service for user " + Slog.i(TAG, "setContentCaptureFeatureEnabled(): disabling service for user " + userId); mDisabledBySettings.put(userId, true); } @@ -401,7 +429,7 @@ public final class ContentCaptureManagerService extends // Called by Shell command. void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) { - Slog.i(mTag, "destroySessions() for userId " + userId); + Slog.i(TAG, "destroySessions() for userId " + userId); enforceCallingPermissionForManagement(); synchronized (mLock) { @@ -424,7 +452,7 @@ public final class ContentCaptureManagerService extends // Called by Shell command. void listSessions(int userId, IResultReceiver receiver) { - Slog.i(mTag, "listSessions() for userId " + userId); + Slog.i(TAG, "listSessions() for userId " + userId); enforceCallingPermissionForManagement(); final Bundle resultData = new Bundle(); @@ -471,14 +499,14 @@ public final class ContentCaptureManagerService extends final int callingUid = Binder.getCallingUid(); final String serviceName = mServiceNameResolver.getServiceName(userId); if (serviceName == null) { - Slog.e(mTag, methodName + ": called by UID " + callingUid + Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but there's no service set for user " + userId); return false; } final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); if (serviceComponent == null) { - Slog.w(mTag, methodName + ": invalid service name: " + serviceName); + Slog.w(TAG, methodName + ": invalid service name: " + serviceName); return false; } @@ -489,11 +517,11 @@ public final class ContentCaptureManagerService extends try { serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId()); } catch (NameNotFoundException e) { - Slog.w(mTag, methodName + ": could not verify UID for " + serviceName); + Slog.w(TAG, methodName + ": could not verify UID for " + serviceName); return false; } if (callingUid != serviceUid) { - Slog.e(mTag, methodName + ": called by UID " + callingUid + ", but service UID is " + Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is " + serviceUid); return false; } @@ -516,7 +544,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage())); } catch (RemoteException e2) { - Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2); + Slog.w(TAG, "Unable to send security exception (" + e + "): ", e2); } } return true; @@ -601,7 +629,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send service component name: " + e); + Slog.w(TAG, "Unable to send service component name: " + e); } } @@ -618,6 +646,35 @@ public final class ContentCaptureManagerService extends } @Override + public void shareData(@NonNull DataShareRequest request, + @NonNull ICancellationSignal clientCancellationSignal, + @NonNull IDataShareWriteAdapter clientAdapter) { + Preconditions.checkNotNull(request); + Preconditions.checkNotNull(clientAdapter); + + assertCalledByPackageOwner(request.getPackageName()); + + final int userId = UserHandle.getCallingUserId(); + synchronized (mLock) { + final ContentCapturePerUserService service = getServiceForUserLocked(userId); + + if (mPackagesWithShareRequests.size() >= MAX_CONCURRENT_FILE_SHARING_REQUESTS + || mPackagesWithShareRequests.contains(request.getPackageName())) { + try { + clientAdapter.error(DataShareWriteAdapter.ERROR_CONCURRENT_REQUEST); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to send error message to client"); + } + return; + } + + service.onDataSharedLocked(request, + new DataShareCallbackDelegate(request, clientCancellationSignal, + clientAdapter)); + } + } + + @Override public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) { boolean enabled; synchronized (mLock) { @@ -632,7 +689,7 @@ public final class ContentCaptureManagerService extends try { result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e); + Slog.w(TAG, "Unable to send isContentCaptureFeatureEnabled(): " + e); } } @@ -652,7 +709,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(componentName)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e); + Slog.w(TAG, "Unable to send getServiceSettingsIntent(): " + e); } } @@ -673,13 +730,13 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(conditions)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send getServiceComponentName(): " + e); + Slog.w(TAG, "Unable to send getServiceComponentName(): " + e); } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return; + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; boolean showHistory = true; if (args != null) { @@ -692,7 +749,7 @@ public final class ContentCaptureManagerService extends pw.println("Usage: dumpsys content_capture [--no-history]"); return; default: - Slog.w(mTag, "Ignoring invalid dump arg: " + arg); + Slog.w(TAG, "Ignoring invalid dump arg: " + arg); } } } @@ -789,7 +846,7 @@ public final class ContentCaptureManagerService extends final ComponentName componentName = ComponentName.unflattenFromString(serviceName); if (componentName == null) { - Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName); + Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName); mServicePackages.remove(userId); } else { mServicePackages.put(userId, componentName.getPackageName()); @@ -815,7 +872,7 @@ public final class ContentCaptureManagerService extends && packageName.equals(mServicePackages.get(userId))) { // No components whitelisted either, but let it go because it's the // service's own package - if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName); + if (verbose) Slog.v(TAG, "getOptionsForPackage() lite for " + packageName); return new ContentCaptureOptions(mDevCfgLoggingLevel); } } @@ -824,7 +881,7 @@ public final class ContentCaptureManagerService extends // Restrict what temporary services can whitelist if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) { if (!packageName.equals(mServicePackages.get(userId))) { - Slog.w(mTag, "Ignoring package " + packageName + " while using temporary " + Slog.w(TAG, "Ignoring package " + packageName + " while using temporary " + "service " + mServicePackages.get(userId)); return null; } @@ -833,7 +890,7 @@ public final class ContentCaptureManagerService extends if (!packageWhitelisted && whitelistedComponents == null) { // No can do! if (verbose) { - Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted"); + Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted"); } return null; } @@ -842,7 +899,7 @@ public final class ContentCaptureManagerService extends mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, whitelistedComponents); - if (verbose) Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options); + if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); return options; } @@ -860,4 +917,179 @@ public final class ContentCaptureManagerService extends } } } + + // TODO(b/148265162): DataShareCallbackDelegate should be a static class keeping week references + // to the needed info + private class DataShareCallbackDelegate extends IDataShareCallback.Stub { + + @NonNull private final DataShareRequest mDataShareRequest; + @NonNull private final ICancellationSignal mClientCancellationSignal; + @NonNull private final IDataShareWriteAdapter mClientAdapter; + + DataShareCallbackDelegate(@NonNull DataShareRequest dataShareRequest, + @NonNull ICancellationSignal clientCancellationSignal, + @NonNull IDataShareWriteAdapter clientAdapter) { + mDataShareRequest = dataShareRequest; + mClientCancellationSignal = clientCancellationSignal; + mClientAdapter = clientAdapter; + } + + @Override + public void accept(ICancellationSignal serviceCancellationSignal, + IDataShareReadAdapter serviceAdapter) throws RemoteException { + Slog.i(TAG, "Data share request accepted by Content Capture service"); + + Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe(); + if (clientPipe == null) { + mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + serviceAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + return; + } + + ParcelFileDescriptor source_in = clientPipe.second; + ParcelFileDescriptor sink_in = clientPipe.first; + + Pair<ParcelFileDescriptor, ParcelFileDescriptor> servicePipe = createPipe(); + if (servicePipe == null) { + bestEffortCloseFileDescriptors(source_in, sink_in); + + mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + serviceAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + return; + } + + ParcelFileDescriptor source_out = servicePipe.second; + ParcelFileDescriptor sink_out = servicePipe.first; + + ICancellationSignal cancellationSignalTransport = + CancellationSignal.createTransport(); + mPackagesWithShareRequests.add(mDataShareRequest.getPackageName()); + + mClientAdapter.write(source_in); + serviceAdapter.start(sink_out, cancellationSignalTransport); + + CancellationSignal cancellationSignal = + CancellationSignal.fromTransport(cancellationSignalTransport); + + cancellationSignal.setOnCancelListener(() -> { + try { + mClientCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to propagate cancel operation to the caller", e); + } + }); + + // File descriptor received by the client app will be a copy of the current one. Close + // the one that belongs to the system server, so there's only 1 open left for the + // current pipe. + bestEffortCloseFileDescriptor(source_in); + + mDataShareExecutor.execute(() -> { + try (InputStream fis = + new ParcelFileDescriptor.AutoCloseInputStream(sink_in); + OutputStream fos = + new ParcelFileDescriptor.AutoCloseOutputStream(source_out)) { + + byte[] byteBuffer = new byte[DATA_SHARE_BYTE_BUFFER_LENGTH]; + while (true) { + int readBytes = fis.read(byteBuffer); + + if (readBytes == -1) { + break; + } + + fos.write(byteBuffer, 0 /* offset */, readBytes); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to pipe client and service streams", e); + } + }); + + mHandler.postDelayed(() -> { + synchronized (mLock) { + mPackagesWithShareRequests.remove(mDataShareRequest.getPackageName()); + + // Interaction finished successfully <=> all data has been written to Content + // Capture Service. If it hasn't been read successfully, service would be able + // to signal through the cancellation signal. + boolean finishedSuccessfully = !sink_in.getFileDescriptor().valid() + && !source_out.getFileDescriptor().valid(); + + if (finishedSuccessfully) { + Slog.i(TAG, "Content capture data sharing session terminated " + + "successfully for package '" + + mDataShareRequest.getPackageName() + + "'"); + } else { + Slog.i(TAG, "Reached the timeout of Content Capture data sharing session " + + "for package '" + + mDataShareRequest.getPackageName() + + "', terminating the pipe."); + } + + // Ensure all the descriptors are closed after the session. + bestEffortCloseFileDescriptors(source_in, sink_in, source_out, sink_out); + + if (!finishedSuccessfully) { + try { + mClientCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to cancel() the client operation", e); + } + try { + serviceCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to cancel() the service operation", e); + } + } + } + }, MAX_DATA_SHARE_FILE_DESCRIPTORS_TTL_MS); + } + + @Override + public void reject() throws RemoteException { + Slog.i(TAG, "Data share request rejected by Content Capture service"); + + mClientAdapter.rejected(); + } + + private Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() { + ParcelFileDescriptor[] fileDescriptors; + try { + fileDescriptors = ParcelFileDescriptor.createPipe(); + } catch (IOException e) { + Slog.e(TAG, "Failed to create a content capture data-sharing pipe", e); + return null; + } + + if (fileDescriptors.length != 2) { + Slog.e(TAG, "Failed to create a content capture data-sharing pipe, " + + "unexpected number of file descriptors"); + return null; + } + + if (!fileDescriptors[0].getFileDescriptor().valid() + || !fileDescriptors[1].getFileDescriptor().valid()) { + Slog.e(TAG, "Failed to create a content capture data-sharing pipe, didn't " + + "receive a pair of valid file descriptors."); + return null; + } + + return Pair.create(fileDescriptors[0], fileDescriptors[1]); + } + + private void bestEffortCloseFileDescriptor(ParcelFileDescriptor fd) { + try { + fd.close(); + } catch (IOException e) { + Slog.e(TAG, "Failed to close a file descriptor", e); + } + } + + private void bestEffortCloseFileDescriptors(ParcelFileDescriptor... fds) { + for (ParcelFileDescriptor fd : fds) { + bestEffortCloseFileDescriptor(fd); + } + } + } } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index a186d4e7f467..0f1122e3886a 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -54,6 +54,7 @@ import android.service.contentcapture.ContentCaptureService; import android.service.contentcapture.ContentCaptureServiceInfo; import android.service.contentcapture.FlushMetrics; import android.service.contentcapture.IContentCaptureServiceCallback; +import android.service.contentcapture.IDataShareCallback; import android.service.contentcapture.SnapshotData; import android.util.ArrayMap; import android.util.ArraySet; @@ -63,6 +64,7 @@ import android.util.SparseBooleanArray; import android.util.StatsLog; import android.view.contentcapture.ContentCaptureCondition; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; @@ -375,6 +377,16 @@ final class ContentCapturePerUserService } @GuardedBy("mLock") + public void onDataSharedLocked(@NonNull DataShareRequest request, + IDataShareCallback.Stub dataShareCallback) { + if (!isEnabledLocked()) { + return; + } + assertCallerLocked(request.getPackageName()); + mRemoteService.onDataShareRequest(request, dataShareCallback); + } + + @GuardedBy("mLock") @Nullable public ComponentName getServiceSettingsActivityLocked() { if (mInfo == null) return null; diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 01d33b0e5445..c16df0f19943 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -29,11 +29,13 @@ import android.os.IBinder; import android.service.contentcapture.ActivityEvent; import android.service.contentcapture.IContentCaptureService; import android.service.contentcapture.IContentCaptureServiceCallback; +import android.service.contentcapture.IDataShareCallback; import android.service.contentcapture.SnapshotData; import android.util.Slog; import android.util.StatsLog; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.DataRemovalRequest; +import android.view.contentcapture.DataShareRequest; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.os.IResultReceiver; @@ -145,6 +147,11 @@ final class RemoteContentCaptureService mComponentName); } + public void onDataShareRequest(@NonNull DataShareRequest request, + @NonNull IDataShareCallback.Stub dataShareCallback) { + scheduleAsyncRequest((s) -> s.onDataShared(request, dataShareCallback)); + } + /** * Called by {@link ContentCaptureServerSession} to notify a high-level activity event. */ diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java index f3647602e69b..a8be66990fff 100644 --- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -16,10 +16,14 @@ package android.app.usage; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.usage.UsageStatsManager.StandbyBuckets; import android.content.ComponentName; +import android.content.LocusId; import android.content.res.Configuration; +import android.os.IBinder; import android.os.UserHandle; import android.os.UserManager; @@ -111,6 +115,20 @@ public abstract class UsageStatsManagerInternal { public abstract void reportContentProviderUsage(String name, String pkgName, @UserIdInt int userId); + + /** + * Reports locusId update for a given activity. + * + * @param activity The component name of the app. + * @param userId The user id of who uses the app. + * @param locusId The locusId a unique, stable id that identifies this activity. + * @param appToken ActivityRecord's appToken. + * {@link UsageEvents} + * @hide + */ + public abstract void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId, + @Nullable LocusId locusId, @NonNull IBinder appToken); + /** * Prepares the UsageStatsService for shutdown. */ diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 994c3147d70c..27b6bfb8f5fd 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -252,11 +252,23 @@ public abstract class PackageManagerInternal { String packageName, int userId); /** + * Do a straight uid lookup for the given package/application in the given user. This enforces + * app visibility rules and permissions. Call {@link #getPackageUidInternal} for the internal + * implementation. + * @deprecated Use {@link PackageManager#getPackageUid(String, int)} + * @return The app's uid, or < 0 if the package was not found in that user + */ + @Deprecated + public abstract int getPackageUid(String packageName, + @PackageInfoFlags int flags, int userId); + + /** * Do a straight uid lookup for the given package/application in the given user. * @see PackageManager#getPackageUidAsUser(String, int, int) * @return The app's uid, or < 0 if the package was not found in that user + * TODO(b/148235092): rename this to getPackageUid */ - public abstract int getPackageUid(String packageName, + public abstract int getPackageUidInternal(String packageName, @PackageInfoFlags int flags, int userId); /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 8f464ff91c62..dd33566322e2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1624,7 +1624,8 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); } - private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( + @VisibleForTesting + NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( NetworkCapabilities nc, int callerPid, int callerUid) { final NetworkCapabilities newNc = new NetworkCapabilities(nc); if (!checkSettingsPermission(callerPid, callerUid)) { @@ -1635,9 +1636,23 @@ public class ConnectivityService extends IConnectivityManager.Stub newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact()); } newNc.setAdministratorUids(Collections.EMPTY_LIST); + + maybeSanitizeLocationInfoForCaller(newNc, callerUid); + return newNc; } + private void maybeSanitizeLocationInfoForCaller( + NetworkCapabilities nc, int callerUid) { + // TODO(b/142072839): Conditionally reset the owner UID if the following + // conditions are not met: + // 1. The destination app is the network owner + // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted + // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted + // 3. The user's location toggle is on + nc.setOwnerUid(INVALID_UID); + } + private LinkProperties linkPropertiesRestrictedForCallerPermissions( LinkProperties lp, int callerPid, int callerUid) { if (lp == null) return new LinkProperties(); @@ -1666,6 +1681,9 @@ public class ConnectivityService extends IConnectivityManager.Stub nc.setSingleUid(Binder.getCallingUid()); } nc.setAdministratorUids(Collections.EMPTY_LIST); + + // Clear owner UID; this can never come from an app. + nc.setOwnerUid(INVALID_UID); } private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) { @@ -5802,7 +5820,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final Set<UidRange> ranges = nai.networkCapabilities.getUids(); - final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid(); + final int vpnAppUid = nai.networkCapabilities.getOwnerUid(); // TODO: this create a window of opportunity for apps to receive traffic between the time // when the old rules are removed and the time when new rules are added. To fix this, // make eBPF support two whitelisted interfaces so here new rules can be added before the @@ -6001,7 +6019,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nc == null || lp == null) return false; return nai.isVPN() && !nai.networkAgentConfig.allowBypass - && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID + && nc.getOwnerUid() != Process.SYSTEM_UID && lp.getInterfaceName() != null && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()); } @@ -6049,12 +6067,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range // to be removed will never overlap with the new range to be added. if (wasFiltering && !prevRanges.isEmpty()) { - mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, - prevNc.getEstablishingVpnAppUid()); + mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid()); } if (shouldFilter && !newRanges.isEmpty()) { - mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, - newNc.getEstablishingVpnAppUid()); + mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid()); } } catch (Exception e) { // Never crash! diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index de0b6fcbd4ae..3b6ff26d5f03 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -52,6 +52,7 @@ import android.location.ILocationListener; import android.location.ILocationManager; import android.location.Location; import android.location.LocationManager; +import android.location.LocationManagerInternal; import android.location.LocationRequest; import android.location.LocationTime; import android.os.Binder; @@ -133,11 +134,12 @@ public class LocationManagerService extends ILocationManager.Stub { */ public static class Lifecycle extends SystemService { - private LocationManagerService mService; + private final LocationManagerService mService; public Lifecycle(Context context) { super(context); mService = new LocationManagerService(context); + LocalServices.addService(LocationManagerInternal.class, mService.new LocalService()); } @Override @@ -465,7 +467,7 @@ public class LocationManagerService extends ILocationManager.Stub { mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); for (LocationProviderManager manager : mProviderManagers) { - manager.onUseableChangedLocked(userId); + manager.onEnabledChangedLocked(userId); } } @@ -633,10 +635,10 @@ public class LocationManagerService extends ILocationManager.Stub { for (LocationProviderManager manager : mProviderManagers) { // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility mSettingsStore.setLocationProviderAllowed(manager.getName(), - manager.isUseable(newUserId), newUserId); + manager.isEnabled(newUserId), newUserId); - manager.onUseableChangedLocked(oldUserId); - manager.onUseableChangedLocked(newUserId); + manager.onEnabledChangedLocked(oldUserId); + manager.onEnabledChangedLocked(newUserId); } } @@ -650,22 +652,22 @@ public class LocationManagerService extends ILocationManager.Stub { // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary protected final MockableLocationProvider mProvider; - // useable state for parent user ids, no entry implies false. location state is only kept + // enabled state for parent user ids, no entry implies false. location state is only kept // for parent user ids, the location state for a profile user id is assumed to be the same // as for the parent. if querying this structure, ensure that the user id being used is a // parent id or the results may be incorrect. @GuardedBy("mLock") - private final SparseArray<Boolean> mUseable; + private final SparseArray<Boolean> mEnabled; private LocationProviderManager(String name) { mName = name; - mUseable = new SparseArray<>(1); + mEnabled = new SparseArray<>(1); // initialize last since this lets our reference escape mProvider = new MockableLocationProvider(mContext, mLock, this); - // we can assume all users start with unuseable location state since the initial state - // of all providers is disabled. no need to initialize mUseable further. + // we can assume all users start with disabled location state since the initial state + // of all providers is disabled. no need to initialize mEnabled further. } public String getName() { @@ -693,13 +695,13 @@ public class LocationManagerService extends ILocationManager.Stub { return mProvider.getState().properties; } - public void setMockProviderEnabled(boolean enabled) { + public void setMockProviderAllowed(boolean enabled) { synchronized (mLock) { if (!mProvider.isMock()) { throw new IllegalArgumentException(mName + " provider is not a test provider"); } - mProvider.setMockProviderEnabled(enabled); + mProvider.setMockProviderAllowed(enabled); } } @@ -760,7 +762,7 @@ public class LocationManagerService extends ILocationManager.Stub { return; } - if (!GPS_PROVIDER.equals(mName) || !isUseable()) { + if (!GPS_PROVIDER.equals(mName) || !isEnabled()) { Slog.w(TAG, "reportLocationBatch() called without user permission"); return; } @@ -771,30 +773,33 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") @Override public void onStateChanged(State oldState, State newState) { - if (oldState.enabled != newState.enabled) { + if (oldState.allowed != newState.allowed) { // it would be more correct to call this for all users, but we know this can // only affect the current user since providers are disabled for non-current // users - onUseableChangedLocked(mUserInfoStore.getCurrentUserId()); + onEnabledChangedLocked(mUserInfoStore.getCurrentUserId()); } } - public boolean isUseable() { - return isUseable(mUserInfoStore.getCurrentUserId()); + public void requestSetAllowed(boolean allowed) { + mProvider.requestSetAllowed(allowed); } - public boolean isUseable(int userId) { + public boolean isEnabled() { + return isEnabled(mUserInfoStore.getCurrentUserId()); + } + + public boolean isEnabled(int userId) { synchronized (mLock) { // normalize user id to always refer to parent since profile state is always the // same as parent state userId = mUserInfoStore.getParentUserId(userId); - - return mUseable.get(userId, Boolean.FALSE); + return mEnabled.get(userId, Boolean.FALSE); } } @GuardedBy("mLock") - public void onUseableChangedLocked(int userId) { + public void onEnabledChangedLocked(int userId) { if (userId == UserHandle.USER_NULL) { // only used during initialization - we don't care about the null user return; @@ -804,36 +809,36 @@ public class LocationManagerService extends ILocationManager.Stub { // as parent state userId = mUserInfoStore.getParentUserId(userId); - // if any property that contributes to "useability" here changes state, it MUST result - // in a direct or indrect call to onUseableChangedLocked. this allows the provider to + // if any property that contributes to "enabled" here changes state, it MUST result + // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to // guarantee that it will always eventually reach the correct state. - boolean useable = (userId == mUserInfoStore.getCurrentUserId()) - && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().enabled; + boolean enabled = (userId == mUserInfoStore.getCurrentUserId()) + && mSettingsStore.isLocationEnabled(userId) && mProvider.getState().allowed; - if (useable == isUseable(userId)) { + if (enabled == isEnabled(userId)) { return; } - mUseable.put(userId, useable); + mEnabled.put(userId, enabled); if (D) { - Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable); + Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled); } // fused and passive provider never get public updates for legacy reasons if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) { // update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility - mSettingsStore.setLocationProviderAllowed(mName, useable, userId); + mSettingsStore.setLocationProviderAllowed(mName, enabled, userId); Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION) .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName) - .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable) + .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } - if (!useable) { + if (!enabled) { // If any provider has been disabled, clear all last locations for all // providers. This is to be on the safe side in case a provider has location // derived from this disabled provider. @@ -841,7 +846,7 @@ public class LocationManagerService extends ILocationManager.Stub { mLastLocationCoarseInterval.clear(); } - updateProviderUseableLocked(this); + updateProviderEnabledLocked(this); } public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { @@ -854,10 +859,10 @@ public class LocationManagerService extends ILocationManager.Stub { pw.increaseIndent(); - boolean useable = isUseable(); - pw.println("useable=" + useable); - if (!useable) { - pw.println("enabled=" + mProvider.getState().enabled); + boolean enabled = isEnabled(); + pw.println("enabled=" + enabled); + if (!enabled) { + pw.println("allowed=" + mProvider.getState().allowed); } pw.println("properties=" + mProvider.getState().properties); @@ -1009,7 +1014,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (manager == null) { continue; } - if (!manager.isUseable() && !isSettingsExemptLocked(updateRecord)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(updateRecord)) { continue; } @@ -1425,7 +1430,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (FUSED_PROVIDER.equals(name)) { continue; } - if (enabledOnly && !manager.isUseable()) { + if (enabledOnly && !manager.isEnabled()) { continue; } if (criteria != null @@ -1467,8 +1472,8 @@ public class LocationManagerService extends ILocationManager.Stub { } @GuardedBy("mLock") - private void updateProviderUseableLocked(LocationProviderManager manager) { - boolean useable = manager.isUseable(); + private void updateProviderEnabledLocked(LocationProviderManager manager) { + boolean enabled = manager.isEnabled(); ArrayList<Receiver> deadReceivers = null; @@ -1486,7 +1491,7 @@ public class LocationManagerService extends ILocationManager.Stub { } // Sends a notification message to the receiver - if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), useable)) { + if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled)) { if (deadReceivers == null) { deadReceivers = new ArrayList<>(); } @@ -1553,7 +1558,7 @@ public class LocationManagerService extends ILocationManager.Stub { } final boolean isBatterySaverDisablingLocation = shouldThrottleRequests || (isForegroundOnlyMode && !record.mIsForegroundUid); - if (!manager.isUseable() || isBatterySaverDisablingLocation) { + if (!manager.isEnabled() || isBatterySaverDisablingLocation) { if (isSettingsExemptLocked(record)) { providerRequest.setLocationSettingsIgnored(true); providerRequest.setLowPowerMode(false); @@ -1970,7 +1975,7 @@ public class LocationManagerService extends ILocationManager.Stub { oldRecord.disposeLocked(false); } - if (!manager.isUseable() && !isSettingsExemptLocked(record)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(record)) { // Notify the listener that updates are currently disabled - but only if the request // does not ignore location settings receiver.callProviderEnabledLocked(name, false); @@ -2082,7 +2087,7 @@ public class LocationManagerService extends ILocationManager.Stub { return null; } - if (!manager.isUseable()) { + if (!manager.isEnabled()) { return null; } @@ -2204,7 +2209,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { LocationProviderManager manager = getLocationProviderManager(location.getProvider()); - if (manager == null || !manager.isUseable()) { + if (manager == null || !manager.isEnabled()) { return false; } @@ -2491,7 +2496,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { LocationProviderManager manager = getLocationProviderManager(providerName); - return manager != null && manager.isUseable(userId); + return manager != null && manager.isEnabled(userId); } } @@ -2549,8 +2554,8 @@ public class LocationManagerService extends ILocationManager.Stub { long now = SystemClock.elapsedRealtime(); - // only update last location for locations that come from useable providers - if (manager.isUseable()) { + // only update last location for locations that come from enabled providers + if (manager.isEnabled()) { updateLastLocationLocked(location, manager.getName()); } @@ -2560,7 +2565,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (lastLocationCoarseInterval == null) { lastLocationCoarseInterval = new Location(location); - if (manager.isUseable()) { + if (manager.isEnabled()) { mLastLocationCoarseInterval.put(manager.getName(), lastLocationCoarseInterval); } } @@ -2593,7 +2598,7 @@ public class LocationManagerService extends ILocationManager.Stub { Receiver receiver = r.mReceiver; boolean receiverDead = false; - if (!manager.isUseable() && !isSettingsExemptLocked(r)) { + if (!manager.isEnabled() && !isSettingsExemptLocked(r)) { continue; } @@ -2812,7 +2817,7 @@ public class LocationManagerService extends ILocationManager.Stub { throw new IllegalArgumentException("provider doesn't exist: " + provider); } - manager.setMockProviderEnabled(enabled); + manager.setMockProviderAllowed(enabled); } @Override @@ -2946,4 +2951,19 @@ public class LocationManagerService extends ILocationManager.Stub { } } } + + private class LocalService extends LocationManagerInternal { + + @Override + public void requestSetProviderAllowed(String provider, boolean allowed) { + Preconditions.checkArgument(provider != null, "invalid null provider"); + + synchronized (mLock) { + LocationProviderManager manager = getLocationProviderManager(provider); + if (manager != null) { + manager.requestSetAllowed(allowed); + } + } + } + } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index ac85bf57e9b0..0a91f9af1cae 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -17,7 +17,15 @@ package com.android.server.am; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; +import static android.os.Process.BLUETOOTH_UID; +import static android.os.Process.NETWORK_STACK_UID; +import static android.os.Process.NFC_UID; +import static android.os.Process.PHONE_UID; +import static android.os.Process.ROOT_UID; +import static android.os.Process.SE_UID; +import static android.os.Process.SYSTEM_UID; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; @@ -45,6 +53,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.app.ServiceStartArgs; +import android.appwidget.AppWidgetManagerInternal; import android.content.ComponentName; import android.content.ComponentName.WithComponentName; import android.content.Context; @@ -56,6 +65,7 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -83,6 +93,7 @@ import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; +import android.widget.Toast; import com.android.internal.R; import com.android.internal.app.procstats.ServiceState; @@ -178,6 +189,8 @@ public final class ActiveServices { String mLastAnrDump; + AppWidgetManagerInternal mAppWidgetManagerInternal; + final Runnable mLastAnrDumpClearer = new Runnable() { @Override public void run() { synchronized (mAm) { @@ -371,6 +384,7 @@ public final class ActiveServices { void systemServicesReady() { AppStateTracker ast = LocalServices.getService(AppStateTracker.class); ast.addListener(new ForcedStandbyListener()); + mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class); } ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) { @@ -643,8 +657,14 @@ public final class ActiveServices { if (allowBackgroundActivityStarts) { r.whitelistBgActivityStartsOnServiceStart(); } - ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); + + if (!r.mAllowWhileInUsePermissionInFgs) { + r.mAllowWhileInUsePermissionInFgs = + shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid, + service, r, allowBackgroundActivityStarts); + } + return cmp; } @@ -1303,6 +1323,15 @@ public final class ActiveServices { + String.format("0x%08X", manifestType) + " in service element of manifest file"); } + if ((foregroundServiceType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 + && !r.mAllowWhileInUsePermissionInFgs) { + // If the foreground service is not started from TOP process, do not allow it to + // have location capability, this prevents BG started FGS to have while-in-use + // location permission. + Slog.w(TAG, + "BG started FGS can not have location capability: service " + + r.shortInstanceName); + } } boolean alreadyStartedOp = false; boolean stopProcStatsOp = false; @@ -1661,7 +1690,6 @@ public final class ActiveServices { return -1; } ServiceRecord s = res.record; - boolean permissionsReviewRequired = false; // If permissions need a review before any of the app components can run, @@ -1810,6 +1838,13 @@ public final class ActiveServices { } } + if (!s.mAllowWhileInUsePermissionInFgs) { + final int callingUid = Binder.getCallingUid(); + s.mAllowWhileInUsePermissionInFgs = + shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid, + service, s, false); + } + if (s.app != null) { if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { s.app.treatLikeActivity = true; @@ -2199,6 +2234,7 @@ public final class ActiveServices { } r = new ServiceRecord(mAm, ss, className, name, definingPackageName, definingUid, filter, sInfo, callingFromFg, res); + r.mRecentCallingPackage = callingPackage; res.setService(r); smap.mServicesByInstanceName.put(name, r); smap.mServicesByIntent.put(filter, r); @@ -3065,6 +3101,7 @@ public final class ActiveServices { r.isForeground = false; r.foregroundId = 0; r.foregroundNoti = null; + r.mAllowWhileInUsePermissionInFgs = false; // Clear start entries. r.clearDeliveredStartsLocked(); @@ -4533,4 +4570,109 @@ public final class ActiveServices { } } } + + /** + * Should allow while-in-use permissions in foreground service or not. + * while-in-use permissions in FGS started from background might be restricted. + * @param callingPackage caller app's package name. + * @param callingUid caller app's uid. + * @param intent intent to start/bind service. + * @param r the service to start. + * @return true if allow, false otherwise. + */ + private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage, + int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) { + // Is the background FGS start restriction turned on? + if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { + return true; + } + // Is the allow activity background start flag on? + if (allowBackgroundActivityStarts) { + return true; + } + + // Is the service in a whitelist? + final boolean hasAllowBackgroundActivityStartsToken = r.app != null + ? r.app.mAllowBackgroundActivityStartsTokens.contains(r) : false; + if (hasAllowBackgroundActivityStartsToken) { + return true; + } + + boolean isCallerSystem = false; + final int callingAppId = UserHandle.getAppId(callingUid); + switch (callingAppId) { + case ROOT_UID: + case SYSTEM_UID: + case NFC_UID: + isCallerSystem = true; + break; + default: + isCallerSystem = false; + break; + } + + if (isCallerSystem) { + return true; + } + + // Is the calling UID at PROCESS_STATE_TOP or above? + final boolean isCallingUidTopApp = appIsTopLocked(callingUid); + if (isCallingUidTopApp) { + return true; + } + // Does the calling UID have any visible activity? + final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid); + if (isCallingUidVisible) { + return true; + } + + r.mInfoDenyWhileInUsePermissionInFgs = + "Background FGS start while-in-use permission restriction [callingPackage: " + + callingPackage + + "; callingUid: " + callingUid + + "; intent: " + intent + + "]"; + return false; + } + + // TODO: remove this toast after feature development is done + private void showWhileInUsePermissionInFgsBlockedToastLocked(String callingPackage) { + final Resources res = mAm.mContext.getResources(); + final String toastMsg = res.getString( + R.string.allow_while_in_use_permission_in_fgs, callingPackage); + mAm.mUiHandler.post(() -> { + Toast.makeText(mAm.mContext, toastMsg, Toast.LENGTH_LONG).show(); + }); + } + + // TODO: remove this toast after feature development is done + // show a toast message to ask user to file a bugreport so we know how many apps are impacted by + // the new background started foreground service while-in-use permission restriction. + void showWhileInUseDebugToastLocked(int uid, int op, int mode) { + StringBuilder sb = new StringBuilder(); + for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { + ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); + if (pr.uid != uid) { + continue; + } + for (int j = pr.services.size() - 1; j >= 0; j--) { + ServiceRecord r = pr.services.valueAt(j); + if (!r.isForeground) { + continue; + } + if (!r.mAllowWhileInUsePermissionInFgs + && r.mInfoDenyWhileInUsePermissionInFgs != null) { + Slog.wtf(TAG, r.mInfoDenyWhileInUsePermissionInFgs + + " affected while-use-permission:" + AppOpsManager.opToPublicName(op)); + sb.append(r.mRecentCallingPackage + " "); + } + } + } + + final String callingPackageStr = sb.toString(); + if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled + && !callingPackageStr.isEmpty()) { + showWhileInUsePermissionInFgsBlockedToastLocked(callingPackageStr); + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index fc4bad722904..8451d6baeb0a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -131,6 +131,12 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED = "default_background_activity_starts_enabled"; + /** + * Default value for mFlagBackgroundFgsStartRestrictionEnabled if not explicitly set in + * Settings.Global. + */ + private static final String KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED = + "default_background_fgs_starts_restriction_enabled"; // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -262,6 +268,16 @@ final class ActivityManagerConstants extends ContentObserver { // If not set explicitly the default is controlled by DeviceConfig. volatile boolean mFlagBackgroundActivityStartsEnabled; + // Indicates whether foreground service starts logging is enabled. + // Controlled by Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED + volatile boolean mFlagForegroundServiceStartsLoggingEnabled; + + // Indicates whether the foreground service background start restriction is enabled. + // When the restriction is enabled, foreground service started from background will not have + // while-in-use permissions like location, camera and microphone. (The foreground service can be + // started, the restriction is on while-in-use permissions.) + volatile boolean mFlagBackgroundFgsStartRestrictionEnabled; + private final ActivityManagerService mService; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -332,6 +348,10 @@ final class ActivityManagerConstants extends ContentObserver { private static final Uri ACTIVITY_STARTS_LOGGING_ENABLED_URI = Settings.Global.getUriFor( Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED); + private static final Uri FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI = + Settings.Global.getUriFor( + Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED); + private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI = Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS); @@ -350,6 +370,9 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED: updateBackgroundActivityStarts(); break; + case KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED: + updateBackgroundFgsStartsRestriction(); + break; case KEY_OOMADJ_UPDATE_POLICY: updateOomAdjUpdatePolicy(); break; @@ -388,6 +411,8 @@ final class ActivityManagerConstants extends ContentObserver { mResolver = resolver; mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this); mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this); + mResolver.registerContentObserver(FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI, + false, this); if (mSystemServerAutomaticHeapDumpEnabled) { mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI, false, this); @@ -402,6 +427,8 @@ final class ActivityManagerConstants extends ContentObserver { updateMaxCachedProcesses(); updateActivityStartsLoggingEnabled(); updateBackgroundActivityStarts(); + updateForegroundServiceStartsLoggingEnabled(); + updateBackgroundFgsStartsRestriction(); updateOomAdjUpdatePolicy(); updateImperceptibleKillExemptions(); } @@ -426,6 +453,8 @@ final class ActivityManagerConstants extends ContentObserver { updateConstants(); } else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) { updateActivityStartsLoggingEnabled(); + } else if (FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI.equals(uri)) { + updateForegroundServiceStartsLoggingEnabled(); } else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) { updateEnableAutomaticSystemServerHeapDumps(); } @@ -522,6 +551,18 @@ final class ActivityManagerConstants extends ContentObserver { /*defaultValue*/ false); } + private void updateForegroundServiceStartsLoggingEnabled() { + mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver, + Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1; + } + + private void updateBackgroundFgsStartsRestriction() { + mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED, + /*defaultValue*/ true); + } + private void updateOomAdjUpdatePolicy() { OOMADJ_UPDATE_QUICK = DeviceConfig.getInt( DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index ed64475084b8..b19a37e0d840 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -50,6 +50,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false; static final boolean DEBUG_COMPACTION = DEBUG_ALL || false; + static final boolean DEBUG_FREEZER = DEBUG_ALL || false; static final boolean DEBUG_LRU = DEBUG_ALL || false; static final boolean DEBUG_MU = DEBUG_ALL || false; static final boolean DEBUG_NETWORK = DEBUG_ALL || false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5596b2fcb762..8b547c6bda42 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -199,6 +199,7 @@ import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentFilter; +import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ActivityPresentationInfo; import android.content.pm.ApplicationInfo; @@ -1798,7 +1799,7 @@ public class ActivityManagerService extends IActivityManager.Stub case KILL_APP_ZYGOTE_MSG: { synchronized (ActivityManagerService.this) { final AppZygote appZygote = (AppZygote) msg.obj; - mProcessList.killAppZygoteIfNeededLocked(appZygote); + mProcessList.killAppZygoteIfNeededLocked(appZygote, false /* force */); } } break; case CHECK_EXCESSIVE_POWER_USE_MSG: { @@ -4656,6 +4657,22 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") + final void forceStopAppZygoteLocked(String packageName, int appId, int userId) { + if (packageName == null) { + return; + } + if (appId < 0) { + try { + appId = UserHandle.getAppId(AppGlobals.getPackageManager() + .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0)); + } catch (RemoteException e) { + } + } + + mProcessList.killAppZygotesLocked(packageName, appId, userId, true /* force */); + } + + @GuardedBy("this") final boolean forceStopPackageLocked(String packageName, int appId, boolean callerWillRestart, boolean purgeCache, boolean doit, boolean evenPersistent, boolean uninstalling, int userId, String reason) { @@ -5779,7 +5796,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (uidRec == null || uidRec.idle) { return false; } - return uidRec.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + return uidRec.getCurProcState() + <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; } } @@ -15634,6 +15652,12 @@ public class ActivityManagerService extends IActivityManager.Stub intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true, false, fullUninstall, userId, removed ? "pkg removed" : "pkg changed"); + } else { + // Kill any app zygotes always, since they can't fork new + // processes with references to the old code + forceStopAppZygoteLocked(ssp, UserHandle.getAppId( + intent.getIntExtra(Intent.EXTRA_UID, -1)), + userId); } final int cmd = killProcess ? ApplicationThreadConstants.PACKAGE_REMOVED @@ -19088,6 +19112,28 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.unregisterProcessObserver(processObserver); } + + @Override + public boolean isUidCurrentlyInstrumented(int uid) { + synchronized (ActivityManagerService.this) { + for (int i = mActiveInstrumentation.size() - 1; i >= 0; i--) { + ActiveInstrumentation activeInst = mActiveInstrumentation.get(i); + if (!activeInst.mFinished && activeInst.mTargetInfo != null + && activeInst.mTargetInfo.uid == uid) { + return true; + } + } + } + return false; + } + + // TODO: remove this toast after feature development is done + @Override + public void showWhileInUseDebugToast(int uid, int op, int mode) { + synchronized (ActivityManagerService.this) { + ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(uid, op, mode); + } + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { @@ -19642,4 +19688,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + + @Override + public void setActivityLocusContext(ComponentName activity, LocusId locusId, IBinder appToken) { + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getCallingUserId(); + if (getPackageManagerInternalLocked().getPackageUid(activity.getPackageName(), + /*flags=*/ 0, userId) != callingUid) { + throw new SecurityException("Calling uid " + callingUid + " cannot set locusId" + + "for package " + activity.getPackageName()); + } + + if (mUsageStatsService != null) { + mUsageStatsService.reportLocusUpdate(activity, userId, locusId, appToken); + } + } } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 3ca5ebce93f2..6819578d9cdc 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.os.Process.THREAD_PRIORITY_FOREGROUND; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import android.app.ActivityManager; @@ -42,6 +43,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.ServiceThread; import java.io.FileOutputStream; +import java.io.FileReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -55,6 +57,7 @@ public final class CachedAppOptimizer { // Flags stored in the DeviceConfig API. @VisibleForTesting static final String KEY_USE_COMPACTION = "use_compaction"; + @VisibleForTesting static final String KEY_USE_FREEZER = "use_freezer"; @VisibleForTesting static final String KEY_COMPACT_ACTION_1 = "compact_action_1"; @VisibleForTesting static final String KEY_COMPACT_ACTION_2 = "compact_action_2"; @VisibleForTesting static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1"; @@ -65,6 +68,8 @@ public final class CachedAppOptimizer { @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6"; @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; + @VisibleForTesting static final String KEY_FREEZER_STATSD_SAMPLE_RATE = + "freeze_statsd_sample_rate"; @VisibleForTesting static final String KEY_COMPACT_FULL_RSS_THROTTLE_KB = "compact_full_rss_throttle_kb"; @VisibleForTesting static final String KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = @@ -85,6 +90,7 @@ public final class CachedAppOptimizer { // Defaults for phenotype flags. @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false; + @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = false; @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE_FLAG; @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL_FLAG; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000; @@ -114,6 +120,13 @@ public final class CachedAppOptimizer { static final int COMPACT_PROCESS_BFGS = 4; static final int COMPACT_PROCESS_MSG = 1; static final int COMPACT_SYSTEM_MSG = 2; + static final int SET_FROZEN_PROCESS_MSG = 3; + + //TODO:change this static definition into a configurable flag. + static final int FREEZE_TIMEOUT_MS = 500; + + static final int DO_FREEZE = 1; + static final int DO_UNFREEZE = 2; /** * This thread must be moved to the system background cpuset. @@ -144,7 +157,9 @@ public final class CachedAppOptimizer { || KEY_COMPACT_THROTTLE_4.equals(name)) { updateCompactionThrottles(); } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { - updateStatsdSampleRate(); + updateCompactStatsdSampleRate(); + } else if (KEY_FREEZER_STATSD_SAMPLE_RATE.equals(name)) { + updateFreezerStatsdSampleRate(); } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) { updateFullRssThrottle(); } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) { @@ -183,9 +198,11 @@ public final class CachedAppOptimizer { @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; @GuardedBy("mPhenotypeFlagLock") private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; + private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER; private final Random mRandom = new Random(); @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; + @VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; + @VisibleForTesting volatile float mFreezerStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting volatile long mFullAnonRssThrottleKb = DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB; @@ -197,6 +214,7 @@ public final class CachedAppOptimizer { // Handler on which compaction runs. private Handler mCompactionHandler; + private Handler mFreezeHandler; // Maps process ID to last compaction statistics for processes that we've fully compacted. Used // when evaluating throttles that we only consider for "full" compaction, so we don't store @@ -238,10 +256,12 @@ public final class CachedAppOptimizer { updateUseCompaction(); updateCompactionActions(); updateCompactionThrottles(); - updateStatsdSampleRate(); + updateCompactStatsdSampleRate(); + updateFreezerStatsdSampleRate(); updateFullRssThrottle(); updateFullDeltaRssThrottle(); updateProcStateThrottle(); + updateUseFreezer(); } Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(), Process.THREAD_GROUP_SYSTEM); @@ -256,6 +276,15 @@ public final class CachedAppOptimizer { } } + /** + * Returns whether freezer is enabled. + */ + public boolean useFreezer() { + synchronized (mPhenotypeFlagLock) { + return mUseFreezer; + } + } + @GuardedBy("mAm") void dump(PrintWriter pw) { pw.println("CachedAppOptimizer settings"); @@ -269,7 +298,7 @@ public final class CachedAppOptimizer { pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull); pw.println(" " + KEY_COMPACT_THROTTLE_5 + "=" + mCompactThrottleBFGS); pw.println(" " + KEY_COMPACT_THROTTLE_6 + "=" + mCompactThrottlePersistent); - pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate); + pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mCompactStatsdSampleRate); pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "=" + mFullAnonRssThrottleKb); pw.println(" " + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + "=" @@ -283,6 +312,8 @@ public final class CachedAppOptimizer { pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size() + " processes."); + pw.println(" " + KEY_USE_FREEZER + "=" + mUseFreezer); + pw.println(" " + KEY_FREEZER_STATSD_SAMPLE_RATE + "=" + mFreezerStatsdSampleRate); if (DEBUG_COMPACTION) { for (Map.Entry<Integer, LastCompactionStats> entry : mLastCompactionStats.entrySet()) { @@ -356,18 +387,76 @@ public final class CachedAppOptimizer { /** * Reads the flag value from DeviceConfig to determine whether app compaction - * should be enabled, and starts the compaction thread if needed. + * should be enabled, and starts the freeze/compaction thread if needed. */ @GuardedBy("mPhenotypeFlagLock") private void updateUseCompaction() { mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION); - if (mUseCompaction && !mCachedAppOptimizerThread.isAlive()) { - mCachedAppOptimizerThread.start(); + + if (mUseCompaction) { + if (!mCachedAppOptimizerThread.isAlive()) { + mCachedAppOptimizerThread.start(); + } + mCompactionHandler = new MemCompactionHandler(); } } + /** + * Determines whether the freezer is correctly supported by this system + */ + public boolean isFreezerSupported() { + boolean supported = false; + FileReader fr = null; + + try { + fr = new FileReader("/dev/freezer/frozen/freezer.killable"); + int i = fr.read(); + + if ((char) i == '1') { + supported = true; + } else { + Slog.w(TAG_AM, "Freezer killability is turned off, disabling freezer"); + } + } catch (java.io.FileNotFoundException e) { + Slog.d(TAG_AM, "Freezer.killable not present, disabling freezer"); + } catch (Exception e) { + Slog.d(TAG_AM, "Unable to read freezer.killable, disabling freezer: " + e.toString()); + } + + if (fr != null) { + try { + fr.close(); + } catch (java.io.IOException e) { + Slog.e(TAG_AM, "Exception closing freezer.killable: " + e.toString()); + } + } + + return supported; + } + + /** + * Reads the flag value from DeviceConfig to determine whether app freezer + * should be enabled, and starts the freeze/compaction thread if needed. + */ + @GuardedBy("mPhenotypeFlagLock") + private void updateUseFreezer() { + if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) { + mUseFreezer = isFreezerSupported(); + } + + if (mUseFreezer) { + Slog.d(TAG_AM, "Freezer enabled"); + if (!mCachedAppOptimizerThread.isAlive()) { + mCachedAppOptimizerThread.start(); + } + + mFreezeHandler = new FreezeHandler(); + } + } + @GuardedBy("mPhenotypeFlagLock") private void updateCompactionActions() { int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -433,10 +522,17 @@ public final class CachedAppOptimizer { } @GuardedBy("mPhenotypeFlagLock") - private void updateStatsdSampleRate() { - mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + private void updateCompactStatsdSampleRate() { + mCompactStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE); - mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate)); + mCompactStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mCompactStatsdSampleRate)); + } + + @GuardedBy("mPhenotypeFlagLock") + private void updateFreezerStatsdSampleRate() { + mFreezerStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_FREEZER_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE); + mFreezerStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mFreezerStatsdSampleRate)); } @GuardedBy("mPhenotypeFlagLock") @@ -507,6 +603,24 @@ public final class CachedAppOptimizer { } } + @GuardedBy("mAm") + void freezeAppAsync(ProcessRecord app) { + mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); + + mFreezeHandler.sendMessageDelayed( + mFreezeHandler.obtainMessage( + SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app), + FREEZE_TIMEOUT_MS); + } + + @GuardedBy("mAm") + void unfreezeAppAsync(ProcessRecord app) { + mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app); + + mFreezeHandler.sendMessage( + mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_UNFREEZE, 0, app)); + } + private static final class LastCompactionStats { private final long[] mRssAfterCompaction; @@ -734,7 +848,7 @@ public final class CachedAppOptimizer { // Note that as above not taking mPhenoTypeFlagLock here to avoid locking // on every single compaction for a flag that will seldom change and the // impact of reading the wrong value here is low. - if (mRandom.nextFloat() < mStatsdSampleRate) { + if (mRandom.nextFloat() < mCompactStatsdSampleRate) { StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction, rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, @@ -768,4 +882,119 @@ public final class CachedAppOptimizer { } } } + + private final class FreezeHandler extends Handler { + private FreezeHandler() { + super(mCachedAppOptimizerThread.getLooper()); + } + + @Override + public void handleMessage(Message msg) { + if (msg.what != SET_FROZEN_PROCESS_MSG) { + return; + } + + if (msg.arg1 == DO_FREEZE) { + freezeProcess((ProcessRecord) msg.obj); + } else if (msg.arg1 == DO_UNFREEZE) { + unfreezeProcess((ProcessRecord) msg.obj); + } + } + + private void freezeProcess(ProcessRecord proc) { + final int pid; + final String name; + final long unfrozenDuration; + final boolean frozen; + + synchronized (mAm) { + pid = proc.pid; + name = proc.processName; + + if (proc.curAdj <= ProcessList.CACHED_APP_MIN_ADJ) { + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, "Skipping freeze for process " + pid + + " " + name + " (not cached)"); + } + return; + } + + if (pid == 0 || proc.frozen) { + // Already frozen or not a real process, either one being + // launched or one being killed + return; + } + + long unfreezeTime = proc.freezeUnfreezeTime; + + try { + Process.setProcessFrozen(pid, proc.uid, true); + + proc.freezeUnfreezeTime = SystemClock.uptimeMillis(); + proc.frozen = true; + } catch (Exception e) { + Slog.w(TAG_AM, "Unable to freeze " + pid + " " + name); + } + + unfrozenDuration = proc.freezeUnfreezeTime - unfreezeTime; + frozen = proc.frozen; + } + + if (frozen) { + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, "froze " + pid + " " + name); + } + + EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name); + } + } + + private void unfreezeProcess(ProcessRecord proc) { + final int pid; + final String name; + final long frozenDuration; + final boolean frozen; + + synchronized (mAm) { + pid = proc.pid; + name = proc.processName; + + if (!proc.frozen) { + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, + "Skipping unfreeze for process " + pid + " " + + name + " (not frozen)"); + } + return; + } + + if (pid == 0) { + // Not a real process, either being launched or killed + return; + } + + long freezeTime = proc.freezeUnfreezeTime; + + try { + Process.setProcessFrozen(proc.pid, proc.uid, false); + + proc.freezeUnfreezeTime = SystemClock.uptimeMillis(); + proc.frozen = false; + } catch (Exception e) { + Slog.w(TAG_AM, "Unable to unfreeze " + pid + " " + name); + } + + frozenDuration = proc.freezeUnfreezeTime - freezeTime; + frozen = proc.frozen; + } + + if (!frozen) { + if (DEBUG_FREEZER) { + Slog.d(TAG_AM, "unfroze " + pid + " " + name); + } + + EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, name); + } + } + } } diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 23674bbd89c7..cc5df4017f28 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -88,3 +88,8 @@ option java_package com.android.server.am # The task is being compacted 30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(DeltaRssTotal|2|2),(DeltaRssFile|2|2),(DeltaRssAnon|2|2),(DeltaRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(DeltaZRAMFree|2|2) +# The task is being frozen +30068 am_freeze (Pid|1|5),(Process Name|3) + +# The task is being unfrozen +30069 am_unfreeze (Pid|1|5),(Process Name|3) diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 04297828ebfc..e9d64913a354 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; +import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; @@ -73,6 +74,7 @@ import android.app.ApplicationExitInfo; import android.app.usage.UsageEvents; import android.compat.Compatibility; import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.compat.annotation.EnabledAfter; import android.content.Context; import android.content.pm.ServiceInfo; @@ -129,13 +131,27 @@ public final class OomAdjuster { * to pass while-in-use capabilities from client process to bound service. In targetSdkVersion * R and above, if client is a TOP activity, when this flag is present, bound service gets all * while-in-use capabilities; when this flag is not present, bound service gets no while-in-use - * capabilitiy from client. + * capability from client. */ @ChangeId @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q) static final long PROCESS_CAPABILITY_CHANGE_ID = 136274596L; /** + * In targetSdkVersion R and above, foreground service has camera and microphone while-in-use + * capability only when the {@link android.R.attr#foregroundServiceType} is configured as + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_CAMERA} and + * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} respectively in the + * manifest file. + * In targetSdkVersion below R, foreground service automatically have camera and microphone + * capabilities. + */ + @ChangeId + //TODO: change to @EnabledAfter when enforcing the feature. + @Disabled + static final long CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID = 136219221L; + + /** * For some direct access we need to power manager. */ PowerManagerInternal mLocalPowerManager; @@ -1412,6 +1428,7 @@ public final class OomAdjuster { } int capabilityFromFGS = 0; // capability from foreground service. + boolean procStateFromFGSClient = false; for (int is = app.services.size() - 1; is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND @@ -1460,22 +1477,13 @@ public final class OomAdjuster { } } - if (s.isForeground) { + if (s.isForeground && s.mAllowWhileInUsePermissionInFgs) { final int fgsType = s.foregroundServiceType; capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0; - if (s.appInfo.targetSdkVersion < Build.VERSION_CODES.R) { - capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA - | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; - } else { - capabilityFromFGS |= - (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0; - capabilityFromFGS |= - (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0; - } + capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA + | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; } ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections(); @@ -1513,13 +1521,17 @@ public final class OomAdjuster { continue; } + int clientAdj = client.getCurRawAdj(); + int clientProcState = client.getCurRawProcState(); + + if (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE) { + procStateFromFGSClient = true; + } + if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) { capability |= client.curCapability; } - int clientAdj = client.getCurRawAdj(); - int clientProcState = client.getCurRawProcState(); - if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) { // If the other app is cached for any reason, for purposes here // we are going to consider it empty. The specific cached state @@ -1941,7 +1953,17 @@ public final class OomAdjuster { // apply capability from FGS. if (app.hasForegroundServices()) { capability |= capabilityFromFGS; + } else if (!ActivityManager.isProcStateBackground(procState)) { + // procState higher than PROCESS_STATE_TRANSIENT_BACKGROUND implicitly has + // camera/microphone capability + if (procState == PROCESS_STATE_FOREGROUND_SERVICE && procStateFromFGSClient) { + // if the FGS state is passed down from client, do not grant implicit capabilities. + } else { + //TODO: remove this line when enforcing the feature. + capability |= PROCESS_CAPABILITY_ALL_IMPLICIT; + } } + // TOP process has all capabilities. if (procState <= PROCESS_STATE_TOP) { capability = PROCESS_CAPABILITY_ALL; @@ -2173,6 +2195,9 @@ public final class OomAdjuster { app.repForegroundActivities = app.hasForegroundActivities(); changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES; } + + updateAppFreezeStateLocked(app); + if (app.getReportedProcState() != app.getCurProcState()) { app.setReportedProcState(app.getCurProcState()); if (app.thread != null) { @@ -2489,4 +2514,18 @@ public final class OomAdjuster { void dumpCachedAppOptimizerSettings(PrintWriter pw) { mCachedAppOptimizer.dump(pw); } + + @GuardedBy("mService") + void updateAppFreezeStateLocked(ProcessRecord app) { + if (!mCachedAppOptimizer.useFreezer()) { + return; + } + + // Use current adjustment when freezing, set adjustment when unfreezing. + if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen) { + mCachedAppOptimizer.freezeAppAsync(app); + } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ && app.frozen) { + mCachedAppOptimizer.unfreezeAppAsync(app); + } + } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 38cb501111ca..b269c38307e7 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1875,11 +1875,11 @@ public final class ProcessList { } @GuardedBy("mService") - public void killAppZygoteIfNeededLocked(AppZygote appZygote) { + public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) { final ApplicationInfo appInfo = appZygote.getAppInfo(); ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote); - if (zygoteProcesses != null && zygoteProcesses.size() == 0) { - // Only remove if no longer in use now + if (zygoteProcesses != null && (force || zygoteProcesses.size() == 0)) { + // Only remove if no longer in use now, or forced kill mAppZygotes.remove(appInfo.processName, appInfo.uid); mAppZygoteProcesses.remove(appZygote); mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo); @@ -1907,7 +1907,7 @@ public final class ProcessList { if (app.removed) { // If we stopped this process because the package hosting it was removed, // there's no point in delaying the app zygote kill. - killAppZygoteIfNeededLocked(appZygote); + killAppZygoteIfNeededLocked(appZygote, false /* force */); } else { Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG); msg.obj = appZygote; @@ -2385,6 +2385,33 @@ public final class ProcessList { } @GuardedBy("mService") + void killAppZygotesLocked(String packageName, int appId, int userId, boolean force) { + // See if there are any app zygotes running for this packageName / UID combination, + // and kill it if so. + final ArrayList<AppZygote> zygotesToKill = new ArrayList<>(); + for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) { + for (int i = 0; i < appZygotes.size(); ++i) { + final int appZygoteUid = appZygotes.keyAt(i); + if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) { + continue; + } + if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) { + continue; + } + final AppZygote appZygote = appZygotes.valueAt(i); + if (packageName != null + && !packageName.equals(appZygote.getAppInfo().packageName)) { + continue; + } + zygotesToKill.add(appZygote); + } + } + for (AppZygote appZygote : zygotesToKill) { + killAppZygoteIfNeededLocked(appZygote, force); + } + } + + @GuardedBy("mService") final boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit, boolean evenPersistent, boolean setRemoved, String reason) { @@ -2461,29 +2488,7 @@ public final class ProcessList { for (int i=0; i<N; i++) { removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason); } - // See if there are any app zygotes running for this packageName / UID combination, - // and kill it if so. - final ArrayList<AppZygote> zygotesToKill = new ArrayList<>(); - for (SparseArray<AppZygote> appZygotes : mAppZygotes.getMap().values()) { - for (int i = 0; i < appZygotes.size(); ++i) { - final int appZygoteUid = appZygotes.keyAt(i); - if (userId != UserHandle.USER_ALL && UserHandle.getUserId(appZygoteUid) != userId) { - continue; - } - if (appId >= 0 && UserHandle.getAppId(appZygoteUid) != appId) { - continue; - } - final AppZygote appZygote = appZygotes.valueAt(i); - if (packageName != null - && !packageName.equals(appZygote.getAppInfo().packageName)) { - continue; - } - zygotesToKill.add(appZygote); - } - } - for (AppZygote appZygote : zygotesToKill) { - killAppZygoteIfNeededLocked(appZygote); - } + killAppZygotesLocked(packageName, appId, userId, false /* force */); mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); return N > 0; } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 0e1e0f9f64f1..1e2dd2deb568 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -163,6 +163,8 @@ class ProcessRecord implements WindowProcessListener { long lastCompactTime; // The last time that this process was compacted int reqCompactAction; // The most recent compaction action requested for this app. int lastCompactAction; // The most recent compaction action performed for this app. + boolean frozen; // True when the process is frozen. + long freezeUnfreezeTime; // Last time the app was (un)frozen, 0 for never private int mCurSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class int trimMemoryLevel; // Last selected memory trimming level @@ -623,7 +625,7 @@ class ProcessRecord implements WindowProcessListener { curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ; mPersistent = false; removed = false; - lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis(); + freezeUnfreezeTime = lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis(); mWindowProcessController = new WindowProcessController( mService.mActivityTaskManager, info, processName, uid, userId, this, this); pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode)); diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index ad316d5fda3f..5d8a0f6161cd 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -135,6 +135,16 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN private Runnable mStartedWhitelistingBgActivityStartsCleanUp; private ProcessRecord mAppForStartedWhitelistingBgActivityStarts; + // allow while-in-use permissions in foreground service or not. + // while-in-use permissions in FGS started from background might be restricted. + boolean mAllowWhileInUsePermissionInFgs; + // information string what/why service is denied while-in-use permissions when + // foreground service is started from background. + // TODO: remove this field after feature development is done + String mInfoDenyWhileInUsePermissionInFgs; + // the most recent package that start/bind this service. + String mRecentCallingPackage; + String stringName; // caching of toString private int lastStartId; // identifier of most recent start request. @@ -293,6 +303,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN ProtoUtils.toDuration(proto, ServiceRecordProto.LAST_ACTIVITY_TIME, lastActivity, now); ProtoUtils.toDuration(proto, ServiceRecordProto.RESTART_TIME, restartTime, now); proto.write(ServiceRecordProto.CREATED_FROM_FG, createdFromFg); + proto.write(ServiceRecordProto.ALLOW_WHILE_IN_USE_PERMISSION_IN_FGS, + mAllowWhileInUsePermissionInFgs); if (startRequested || delayedStop || lastStartId != 0) { long startToken = proto.start(ServiceRecordProto.START); @@ -389,6 +401,10 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts="); pw.println(mHasStartedWhitelistingBgActivityStarts); } + if (mAllowWhileInUsePermissionInFgs) { + pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs="); + pw.println(mAllowWhileInUsePermissionInFgs); + } if (delayed) { pw.print(prefix); pw.print("delayed="); pw.println(delayed); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 08136a3cb9e5..62596de7b9a6 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -24,6 +24,7 @@ import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME; import static android.app.AppOpsManager.FILTER_BY_UID; import static android.app.AppOpsManager.HistoricalOpsRequestFilter; +import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.NoteOpEvent; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_COARSE_LOCATION; @@ -50,12 +51,14 @@ import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; +import static android.os.Process.STATSD_UID; import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -288,6 +291,8 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") private SparseArray<List<Integer>> mSwitchOpToOps; + private ActivityManagerInternal mActivityManagerInternal; + /** * An unsynchronized pool of {@link OpEventProxyInfo} objects. */ @@ -423,7 +428,7 @@ public class AppOpsService extends IAppOpsService.Stub { final Constants mConstants; @VisibleForTesting - static final class UidState { + final class UidState { public final int uid; public int state = UID_STATE_CACHED; @@ -431,6 +436,8 @@ public class AppOpsService extends IAppOpsService.Stub { public long pendingStateCommitTime; public int capability; public int pendingCapability; + public boolean appWidgetVisible; + public boolean pendingAppWidgetVisible; public ArrayMap<String, Ops> pkgOps; public SparseIntArray opModes; @@ -439,6 +446,8 @@ public class AppOpsService extends IAppOpsService.Stub { public SparseBooleanArray foregroundOps; public boolean hasForegroundWatchers; + public long lastTimeShowDebugToast; + public UidState(int uid) { this.uid = uid; } @@ -457,7 +466,9 @@ public class AppOpsService extends IAppOpsService.Stub { int evalMode(int op, int mode) { if (mode == AppOpsManager.MODE_FOREGROUND) { - if (state <= UID_STATE_TOP) { + if (appWidgetVisible) { + return MODE_ALLOWED; + } else if (state <= UID_STATE_TOP) { // process is in foreground. return AppOpsManager.MODE_ALLOWED; } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) { @@ -467,14 +478,28 @@ public class AppOpsService extends IAppOpsService.Stub { case AppOpsManager.OP_COARSE_LOCATION: case AppOpsManager.OP_MONITOR_LOCATION: case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION: - return ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) - ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED; + if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) { + return AppOpsManager.MODE_ALLOWED; + } else { + maybeShowWhileInUseDebugToast(op, mode); + return AppOpsManager.MODE_IGNORED; + } case OP_CAMERA: - return ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) - ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED; + if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { + return AppOpsManager.MODE_ALLOWED; + } else { + //TODO change to MODE_IGNORED when enforcing the feature. + maybeShowWhileInUseDebugToast(op, mode); + return AppOpsManager.MODE_ALLOWED; + } case OP_RECORD_AUDIO: - return ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) - ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED; + if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { + return AppOpsManager.MODE_ALLOWED; + } else { + //TODO change to MODE_IGNORED when enforcing the feature. + maybeShowWhileInUseDebugToast(op, mode); + return AppOpsManager.MODE_ALLOWED; + } default: return AppOpsManager.MODE_ALLOWED; } @@ -482,6 +507,27 @@ public class AppOpsService extends IAppOpsService.Stub { // process is not in foreground. return AppOpsManager.MODE_IGNORED; } + } else if (mode == AppOpsManager.MODE_ALLOWED) { + switch (op) { + case OP_CAMERA: + if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { + return AppOpsManager.MODE_ALLOWED; + } else { + //TODO change to MODE_IGNORED when enforcing the feature. + maybeShowWhileInUseDebugToast(op, mode); + return AppOpsManager.MODE_ALLOWED; + } + case OP_RECORD_AUDIO: + if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { + return AppOpsManager.MODE_ALLOWED; + } else { + //TODO change to MODE_IGNORED when enforcing the feature. + maybeShowWhileInUseDebugToast(op, mode); + return AppOpsManager.MODE_ALLOWED; + } + default: + return MODE_ALLOWED; + } } return mode; } @@ -530,6 +576,23 @@ public class AppOpsService extends IAppOpsService.Stub { } foregroundOps = which; } + + // TODO: remove this toast after feature development is done + // If the procstate is foreground service and while-in-use permission is denied, show a + // toast message to ask user to file a bugreport so we know how many apps are impacted by + // the new background started foreground service while-in-use permission restriction. + void maybeShowWhileInUseDebugToast(int op, int mode) { + if (state != UID_STATE_FOREGROUND_SERVICE) { + return; + } + final long now = System.currentTimeMillis(); + if (lastTimeShowDebugToast == 0 || now - lastTimeShowDebugToast > 600000) { + lastTimeShowDebugToast = now; + mHandler.sendMessage(PooledLambda.obtainMessage( + ActivityManagerInternal::showWhileInUseDebugToast, + mActivityManagerInternal, uid, op, mode)); + } + } } final static class Ops extends SparseArray<Op> { @@ -1476,6 +1539,7 @@ public class AppOpsService extends IAppOpsService.Stub { } }); } + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); } public void packageRemoved(int uid, String packageName) { @@ -1760,6 +1824,15 @@ public class AppOpsService extends IAppOpsService.Stub { beginTimeMillis, endTimeMillis, flags); Objects.requireNonNull(callback, "callback cannot be null"); + ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); + boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid()); + boolean isCallerStatsCollector = Binder.getCallingUid() == STATSD_UID; + + if (!isCallerStatsCollector && !isCallerInstrumented) { + mHandler.post(() -> callback.sendResult(new Bundle())); + return; + } + mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps"); @@ -2993,7 +3066,6 @@ public class AppOpsService extends IAppOpsService.Stub { } if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid + " package " + resolvedPackageName); - try { featureOp.started(clientId, uidState.state); } catch (RemoteException e) { @@ -3216,7 +3288,9 @@ public class AppOpsService extends IAppOpsService.Stub { final long firstUnrestrictedUidState = resolveFirstUnrestrictedUidState(code); final boolean resolvedLastFg = uidState.state <= firstUnrestrictedUidState; final boolean resolvedNowFg = uidState.pendingState <= firstUnrestrictedUidState; - if (resolvedLastFg == resolvedNowFg) { + if (resolvedLastFg == resolvedNowFg + && uidState.capability == uidState.pendingCapability + && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) { continue; } final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); @@ -3250,9 +3324,25 @@ public class AppOpsService extends IAppOpsService.Stub { } uidState.state = uidState.pendingState; uidState.capability = uidState.pendingCapability; + uidState.appWidgetVisible = uidState.pendingAppWidgetVisible; uidState.pendingStateCommitTime = 0; } + private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) { + synchronized (this) { + for (int i = uidPackageNames.size() - 1; i >= 0; i--) { + final int uid = uidPackageNames.keyAt(i); + final UidState uidState = getUidStateLocked(uid, true); + if (uidState != null && (uidState.pendingAppWidgetVisible != visible)) { + uidState.pendingAppWidgetVisible = visible; + if (uidState.pendingAppWidgetVisible != uidState.appWidgetVisible) { + commitUidPendingStateLocked(uidState); + } + } + } + } + } + /** * Verify that package belongs to uid and return whether the package is privileged. * @@ -4475,8 +4565,6 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(" Limit output to data associated with the given feature id."); pw.println(" --watchers"); pw.println(" Only output the watcher sections."); - pw.println(" --history"); - pw.println(" Output the historical data."); } private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterFeatureId, @@ -4609,6 +4697,7 @@ public class AppOpsService extends IAppOpsService.Stub { int dumpUid = Process.INVALID_UID; int dumpMode = -1; boolean dumpWatchers = false; + // TODO ntmyren: Remove the dumpHistory and dumpFilter boolean dumpHistory = false; @HistoricalOpsRequestFilter int dumpFilter = 0; @@ -4671,8 +4760,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } else if ("--watchers".equals(arg)) { dumpWatchers = true; - } else if ("--history".equals(arg)) { - dumpHistory = true; } else if (arg.length() > 0 && arg.charAt(0) == '-'){ pw.println("Unknown option: " + arg); return; @@ -5491,5 +5578,11 @@ public class AppOpsService extends IAppOpsService.Stub { mProfileOwners = owners; } } + + @Override + public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, + boolean visible) { + AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible); + } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 0c9abae2e0fc..423e0212dfd6 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -954,7 +954,7 @@ public class Vpn { NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; - mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid()); + mNetworkCapabilities.setOwnerUid(Binder.getCallingUid()); mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle, mConfig.allowedApplications, mConfig.disallowedApplications)); long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index e7f537b897b9..4ddc391bd889 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -3451,6 +3451,7 @@ public class SyncManager { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: account doesn't exist."); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist."); return SYNC_OP_STATE_INVALID; } // Drop this sync request if it isn't syncable. @@ -3460,12 +3461,14 @@ public class SyncManager { Slog.v(TAG, " Dropping sync operation: " + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS"); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS"); return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS; } if (state == AuthorityInfo.NOT_SYNCABLE) { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE"); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE"); return SYNC_OP_STATE_INVALID; } @@ -3484,6 +3487,7 @@ public class SyncManager { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: disallowed by settings/network."); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network"); return SYNC_OP_STATE_INVALID; } return SYNC_OP_STATE_VALID; diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index aa39926d2310..6ff276703443 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -87,7 +87,7 @@ public abstract class BrightnessMappingStrategy { } BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( luxLevels, brightnessLevelsNits); - builder.setShortTermModelTimeout(shortTermModelTimeout); + builder.setShortTermModelTimeoutMillis(shortTermModelTimeout); builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange, @@ -739,10 +739,10 @@ public abstract class BrightnessMappingStrategy { @Override public long getShortTermModelTimeout() { - if (mConfig.getShortTermModelTimeout() >= 0) { - return mConfig.getShortTermModelTimeout(); + if (mConfig.getShortTermModelTimeoutMillis() >= 0) { + return mConfig.getShortTermModelTimeoutMillis(); } else { - return mDefaultConfig.getShortTermModelTimeout(); + return mDefaultConfig.getShortTermModelTimeoutMillis(); } } diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 442211f451ee..11fe15f0e12b 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -17,16 +17,15 @@ package com.android.server.integrity; import static android.content.Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION; +import static android.content.Intent.EXTRA_LONG_VERSION_CODE; import static android.content.Intent.EXTRA_ORIGINATING_UID; import static android.content.Intent.EXTRA_PACKAGE_NAME; -import static android.content.Intent.EXTRA_VERSION_CODE; import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS; import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE; import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS; +import static android.content.integrity.IntegrityUtils.getHexDigest; import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; -import static com.android.server.integrity.IntegrityUtils.getHexDigest; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -47,7 +46,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.os.RemoteException; import android.util.Slog; import android.util.StatsLog; @@ -75,18 +73,29 @@ import java.util.Map; /** Implementation of {@link AppIntegrityManagerService}. */ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { + /** + * This string will be used as the "installer" for formula evaluation when the app's installer + * cannot be determined. + * + * <p>This may happen for various reasons. e.g., the installing app's package name may not match + * its UID. + */ + private static final String UNKNOWN_INSTALLER = ""; + /** + * This string will be used as the "installer" for formula evaluation when the app is being + * installed via ADB. + */ + private static final String ADB_INSTALLER = "adb"; + private static final String TAG = "AppIntegrityManagerServiceImpl"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; - private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); private static final String PACKAGE_INSTALLER = "com.google.android.packageinstaller"; private static final String BASE_APK_FILE = "base.apk"; private static final String ALLOWED_INSTALLERS_METADATA_NAME = "allowed-installers"; private static final String ALLOWED_INSTALLER_DELIMITER = ","; private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|"; - private static final String ADB_INSTALLER = "adb"; - private static final String UNKNOWN_INSTALLER = ""; private static final String INSTALLER_CERT_NOT_APPLICABLE = ""; // Access to files inside mRulesDir is protected by mRulesLock; @@ -148,8 +157,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { @Override public void updateRuleSet( - String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) - throws RemoteException { + String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) { String ruleProvider = getCallerPackageNameOrThrow(); mHandler.post( @@ -180,7 +188,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } @Override - public String getCurrentRuleSetVersion() throws RemoteException { + public String getCurrentRuleSetVersion() { getCallerPackageNameOrThrow(); RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata(); @@ -190,7 +198,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } @Override - public String getCurrentRuleSetProvider() throws RemoteException { + public String getCurrentRuleSetProvider() { getCallerPackageNameOrThrow(); RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata(); @@ -202,14 +210,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private void handleIntegrityVerification(Intent intent) { int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); - // Fail early if we don't have any rules at all. - if (!mIntegrityFileManager.initialized()) { - Slog.i(TAG, "Rules not initialized. Skipping integrity check."); - mPackageManagerInternal.setIntegrityVerificationResult( - verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - return; - } - try { Slog.i(TAG, "Received integrity verification intent " + intent.toString()); Slog.i(TAG, "Extras " + intent.getExtras()); @@ -241,7 +241,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { builder.setPackageName(getPackageNameNormalized(packageName)); builder.setAppCertificate(appCert == null ? "" : appCert); - builder.setVersionCode(intent.getIntExtra(EXTRA_VERSION_CODE, -1)); + builder.setVersionCode(intent.getLongExtra(EXTRA_LONG_VERSION_CODE, -1)); builder.setInstallerName(getPackageNameNormalized(installerPackageName)); builder.setInstallerCertificate( getInstallerCertificateFingerprint(installerPackageName)); @@ -262,14 +262,11 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { + " due to " + result.getRule()); - // TODO(b/147095027): Remove when the proto type is fixed. - int dummyBreakageFixerInt = 0; - StatsLog.write( StatsLog.INTEGRITY_CHECK_RESULT_REPORTED, packageName, appCert, - dummyBreakageFixerInt, + appInstallMetadata.getVersionCode(), installerPackageName, getLoggingResponse(result), isCausedByAppCertRule(result), diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java index 07eacbfd87dd..79e69e15ff67 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java @@ -19,7 +19,7 @@ package com.android.server.integrity.engine; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Slog; @@ -65,7 +65,7 @@ public class RuleEvaluationEngine { * Load, and match the list of rules against an app install metadata. * * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules - * against. + * against. * @return result of the integrity check */ public IntegrityCheckResult evaluate( @@ -76,6 +76,11 @@ public class RuleEvaluationEngine { } private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) { + if (!mIntegrityFileManager.initialized()) { + Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules."); + return new ArrayList<>(); + } + try { return mIntegrityFileManager.readRules(appInstallMetadata); } catch (Exception e) { @@ -89,14 +94,14 @@ public class RuleEvaluationEngine { return Optional.empty(); } - List<Formula> formulas = new ArrayList<>(allowedInstallers.size()); + List<IntegrityFormula> formulas = new ArrayList<>(allowedInstallers.size()); allowedInstallers.forEach( (installer, cert) -> { formulas.add(allowedInstallerFormula(installer, cert)); }); // We need this special case since OR-formulas require at least two operands. - Formula allInstallersFormula = + IntegrityFormula allInstallersFormula = formulas.size() == 1 ? formulas.get(0) : new CompoundFormula(CompoundFormula.OR, formulas); @@ -108,7 +113,7 @@ public class RuleEvaluationEngine { Rule.DENY)); } - private static Formula allowedInstallerFormula(String installer, String cert) { + private static IntegrityFormula allowedInstallerFormula(String installer, String cert) { return new CompoundFormula( CompoundFormula.AND, Arrays.asList( @@ -117,8 +122,7 @@ public class RuleEvaluationEngine { installer, /* isHashedValue= */ false), new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_CERTIFICATE, - cert, - /* isHashedValue= */ false))); + AtomicFormula.INSTALLER_CERTIFICATE, cert, /* isHashedValue= */ + false))); } } diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java index b1c20d27c792..66537ff6105e 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java @@ -22,7 +22,6 @@ import static android.content.integrity.Rule.FORCE_ALLOW; import android.annotation.NonNull; import android.content.integrity.AppInstallMetadata; import android.content.integrity.Rule; -import android.util.Slog; import com.android.server.integrity.model.IntegrityCheckResult; @@ -35,8 +34,6 @@ import java.util.List; */ final class RuleEvaluator { - private static final String TAG = "RuleEvaluator"; - /** * Match the list of rules against an app install metadata. * @@ -53,7 +50,7 @@ final class RuleEvaluator { List<Rule> rules, AppInstallMetadata appInstallMetadata) { List<Rule> matchedRules = new ArrayList<>(); for (Rule rule : rules) { - if (rule.getFormula().isSatisfied(appInstallMetadata)) { + if (rule.getFormula().matches(appInstallMetadata)) { matchedRules.add(rule); } } @@ -71,8 +68,7 @@ final class RuleEvaluator { case FORCE_ALLOW: return IntegrityCheckResult.allow(rule); default: - Slog.e(TAG, "Matched an unknown effect rule: " + rule); - return IntegrityCheckResult.allow(); + throw new IllegalArgumentException("Matched an unknown effect rule: " + rule); } } return denied ? IntegrityCheckResult.deny(denyRule) : IntegrityCheckResult.allow(); diff --git a/services/core/java/com/android/server/integrity/model/BitOutputStream.java b/services/core/java/com/android/server/integrity/model/BitOutputStream.java index 7d1bb3fb8203..14b35fd016eb 100644 --- a/services/core/java/com/android/server/integrity/model/BitOutputStream.java +++ b/services/core/java/com/android/server/integrity/model/BitOutputStream.java @@ -61,7 +61,7 @@ public class BitOutputStream { /** * Set the next bit in the stream to value. * - * @param value The value to set the bit to. + * @param value The value to set the bit to */ public void setNext(boolean value) throws IOException { int byteToWrite = mNextBitIndex / BYTE_BITS; diff --git a/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java b/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java index 2c5b7d3c122c..f09e035ecc78 100644 --- a/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java +++ b/services/core/java/com/android/server/integrity/parser/BinaryFileOperations.java @@ -19,7 +19,8 @@ package com.android.server.integrity.parser; import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS; import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; -import com.android.server.integrity.IntegrityUtils; +import android.content.integrity.IntegrityUtils; + import com.android.server.integrity.model.BitInputStream; import java.io.IOException; diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java index 90954ff21d57..4b8efafcb6b0 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java @@ -35,7 +35,7 @@ import static com.android.server.integrity.parser.BinaryFileOperations.getString import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import com.android.server.integrity.model.BitInputStream; @@ -121,7 +121,7 @@ public class RuleBinaryParser implements RuleParser { } private Rule parseRule(BitInputStream bitInputStream) throws IOException { - Formula formula = parseFormula(bitInputStream); + IntegrityFormula formula = parseFormula(bitInputStream); int effect = bitInputStream.getNext(EFFECT_BITS); if (bitInputStream.getNext(SIGNAL_BIT) != 1) { @@ -131,7 +131,7 @@ public class RuleBinaryParser implements RuleParser { return new Rule(formula, effect); } - private Formula parseFormula(BitInputStream bitInputStream) throws IOException { + private IntegrityFormula parseFormula(BitInputStream bitInputStream) throws IOException { int separator = bitInputStream.getNext(SEPARATOR_BITS); switch (separator) { case ATOMIC_FORMULA_START: @@ -148,9 +148,9 @@ public class RuleBinaryParser implements RuleParser { private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException { int connector = bitInputStream.getNext(CONNECTOR_BITS); - List<Formula> formulas = new ArrayList<>(); + List<IntegrityFormula> formulas = new ArrayList<>(); - Formula parsedFormula = parseFormula(bitInputStream); + IntegrityFormula parsedFormula = parseFormula(bitInputStream); while (parsedFormula != null) { formulas.add(parsedFormula); parsedFormula = parseFormula(bitInputStream); @@ -173,8 +173,11 @@ public class RuleBinaryParser implements RuleParser { String stringValue = getStringValue(bitInputStream, valueSize, isHashedValue); return new AtomicFormula.StringAtomicFormula(key, stringValue, isHashedValue); case AtomicFormula.VERSION_CODE: - int intValue = getIntValue(bitInputStream); - return new AtomicFormula.IntAtomicFormula(key, operator, intValue); + // TODO(b/147880712): temporary hack until our input handles long + long upper = getIntValue(bitInputStream); + long lower = getIntValue(bitInputStream); + long longValue = (upper << 32) | lower; + return new AtomicFormula.LongAtomicFormula(key, operator, longValue); case AtomicFormula.PRE_INSTALLED: boolean booleanValue = getBooleanValue(bitInputStream); return new AtomicFormula.BooleanAtomicFormula(key, booleanValue); diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java index 53b0c2e59453..f37ca1efce13 100644 --- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java +++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java @@ -18,7 +18,7 @@ package com.android.server.integrity.parser; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Xml; @@ -107,7 +107,7 @@ public final class RuleXmlParser implements RuleParser { } private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException { - Formula formula = null; + IntegrityFormula formula = null; int effect = Integer.parseInt(extractAttributeValue(parser, EFFECT_ATTRIBUTE).orElse("-1")); int eventType; @@ -139,11 +139,11 @@ public final class RuleXmlParser implements RuleParser { return new Rule(formula, effect); } - private static Formula parseCompoundFormula(XmlPullParser parser) + private static IntegrityFormula parseCompoundFormula(XmlPullParser parser) throws IOException, XmlPullParserException { int connector = Integer.parseInt(extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1")); - List<Formula> formulas = new ArrayList<>(); + List<IntegrityFormula> formulas = new ArrayList<>(); int eventType; while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -175,7 +175,7 @@ public final class RuleXmlParser implements RuleParser { return new CompoundFormula(connector, formulas); } - private static Formula parseAtomicFormula(XmlPullParser parser) + private static IntegrityFormula parseAtomicFormula(XmlPullParser parser) throws IOException, XmlPullParserException { int key = Integer.parseInt(extractAttributeValue(parser, KEY_ATTRIBUTE).orElse("-1")); int operator = @@ -193,7 +193,7 @@ public final class RuleXmlParser implements RuleParser { return constructAtomicFormulaBasedOnKey(key, operator, value, isHashedValue); } - private static Formula constructAtomicFormulaBasedOnKey( + private static IntegrityFormula constructAtomicFormulaBasedOnKey( @AtomicFormula.Key int key, @AtomicFormula.Operator int operator, String value, @@ -208,7 +208,7 @@ public final class RuleXmlParser implements RuleParser { case AtomicFormula.PRE_INSTALLED: return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value)); case AtomicFormula.VERSION_CODE: - return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value)); + return new AtomicFormula.LongAtomicFormula(key, operator, Integer.parseInt(value)); default: throw new RuntimeException(String.format("Found unexpected key: %d", key)); } diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java index f5ed975bf772..d01499668e8c 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java @@ -36,11 +36,11 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; import com.android.internal.util.Preconditions; -import com.android.server.integrity.IntegrityUtils; import com.android.server.integrity.model.BitOutputStream; import com.android.server.integrity.model.ByteTrackedOutputStream; @@ -192,7 +192,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(); } - private void serializeFormula(Formula formula, BitOutputStream bitOutputStream) + private void serializeFormula(IntegrityFormula formula, BitOutputStream bitOutputStream) throws IOException { if (formula instanceof AtomicFormula) { serializeAtomicFormula((AtomicFormula) formula, bitOutputStream); @@ -212,7 +212,7 @@ public class RuleBinarySerializer implements RuleSerializer { bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_START); bitOutputStream.setNext(CONNECTOR_BITS, compoundFormula.getConnector()); - for (Formula formula : compoundFormula.getFormulas()) { + for (IntegrityFormula formula : compoundFormula.getFormulas()) { serializeFormula(formula, bitOutputStream); } bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_END); @@ -234,11 +234,14 @@ public class RuleBinarySerializer implements RuleSerializer { stringAtomicFormula.getValue(), stringAtomicFormula.getIsHashedValue(), bitOutputStream); - } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { - AtomicFormula.IntAtomicFormula intAtomicFormula = - (AtomicFormula.IntAtomicFormula) atomicFormula; - bitOutputStream.setNext(OPERATOR_BITS, intAtomicFormula.getOperator()); - serializeIntValue(intAtomicFormula.getValue(), bitOutputStream); + } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) { + AtomicFormula.LongAtomicFormula longAtomicFormula = + (AtomicFormula.LongAtomicFormula) atomicFormula; + bitOutputStream.setNext(OPERATOR_BITS, longAtomicFormula.getOperator()); + // TODO(b/147880712): Temporary hack until we support long values in bitOutputStream + long value = longAtomicFormula.getValue(); + serializeIntValue((int) (value >>> 32), bitOutputStream); + serializeIntValue((int) value, bitOutputStream); } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = (AtomicFormula.BooleanAtomicFormula) atomicFormula; diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java index 7d9a90188983..6f7d172aabcc 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java @@ -22,7 +22,7 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import java.util.ArrayList; @@ -76,15 +76,15 @@ class RuleIndexingDetailsIdentifier { return typeOrganizedRuleMap; } - private static RuleIndexingDetails getIndexingDetails(Formula formula) { + private static RuleIndexingDetails getIndexingDetails(IntegrityFormula formula) { switch (formula.getTag()) { - case Formula.COMPOUND_FORMULA_TAG: + case IntegrityFormula.COMPOUND_FORMULA_TAG: return getIndexingDetailsForCompoundFormula((CompoundFormula) formula); - case Formula.STRING_ATOMIC_FORMULA_TAG: + case IntegrityFormula.STRING_ATOMIC_FORMULA_TAG: return getIndexingDetailsForStringAtomicFormula( (AtomicFormula.StringAtomicFormula) formula); - case Formula.INT_ATOMIC_FORMULA_TAG: - case Formula.BOOLEAN_ATOMIC_FORMULA_TAG: + case IntegrityFormula.LONG_ATOMIC_FORMULA_TAG: + case IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG: // Package name and app certificate related formulas are string atomic formulas. return new RuleIndexingDetails(NOT_INDEXED); default: @@ -96,7 +96,7 @@ class RuleIndexingDetailsIdentifier { private static RuleIndexingDetails getIndexingDetailsForCompoundFormula( CompoundFormula compoundFormula) { int connector = compoundFormula.getConnector(); - List<Formula> formulas = compoundFormula.getFormulas(); + List<IntegrityFormula> formulas = compoundFormula.getFormulas(); switch (connector) { case CompoundFormula.AND: diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java index 8f164e645434..6e1218064096 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java +++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java @@ -22,7 +22,7 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import android.util.Xml; @@ -128,7 +128,8 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.endTag(NAMESPACE, RULE_TAG); } - private void serializeFormula(Formula formula, XmlSerializer xmlSerializer) throws IOException { + private void serializeFormula(IntegrityFormula formula, XmlSerializer xmlSerializer) + throws IOException { if (formula instanceof AtomicFormula) { serializeAtomicFormula((AtomicFormula) formula, xmlSerializer); } else if (formula instanceof CompoundFormula) { @@ -147,7 +148,7 @@ public class RuleXmlSerializer implements RuleSerializer { xmlSerializer.startTag(NAMESPACE, COMPOUND_FORMULA_TAG); serializeAttributeValue( CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()), xmlSerializer); - for (Formula formula : compoundFormula.getFormulas()) { + for (IntegrityFormula formula : compoundFormula.getFormulas()) { serializeFormula(formula, xmlSerializer); } xmlSerializer.endTag(NAMESPACE, COMPOUND_FORMULA_TAG); @@ -171,14 +172,14 @@ public class RuleXmlSerializer implements RuleSerializer { String.valueOf( ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()), xmlSerializer); - } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) { + } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) { serializeAttributeValue( OPERATOR_ATTRIBUTE, - String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()), + String.valueOf(((AtomicFormula.LongAtomicFormula) atomicFormula).getOperator()), xmlSerializer); serializeAttributeValue( VALUE_ATTRIBUTE, - String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()), + String.valueOf(((AtomicFormula.LongAtomicFormula) atomicFormula).getValue()), xmlSerializer); } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { serializeAttributeValue( diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java index ed6a759409d4..5afa48a2b34d 100644 --- a/services/core/java/com/android/server/location/AbstractLocationProvider.java +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -79,9 +79,9 @@ public abstract class AbstractLocationProvider { Collections.emptySet()); /** - * The provider's enabled state. + * The provider's allowed state. */ - public final boolean enabled; + public final boolean allowed; /** * The provider's properties. @@ -93,18 +93,18 @@ public abstract class AbstractLocationProvider { */ public final Set<String> providerPackageNames; - private State(boolean enabled, ProviderProperties properties, + private State(boolean allowed, ProviderProperties properties, Set<String> providerPackageNames) { - this.enabled = enabled; + this.allowed = allowed; this.properties = properties; this.providerPackageNames = Objects.requireNonNull(providerPackageNames); } - private State withEnabled(boolean enabled) { - if (enabled == this.enabled) { + private State withAllowed(boolean allowed) { + if (allowed == this.allowed) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -112,7 +112,7 @@ public abstract class AbstractLocationProvider { if (properties.equals(this.properties)) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -120,7 +120,7 @@ public abstract class AbstractLocationProvider { if (providerPackageNames.equals(this.providerPackageNames)) { return this; } else { - return new State(enabled, properties, providerPackageNames); + return new State(allowed, properties, providerPackageNames); } } @@ -133,13 +133,13 @@ public abstract class AbstractLocationProvider { return false; } State state = (State) o; - return enabled == state.enabled && properties == state.properties + return allowed == state.allowed && properties == state.properties && providerPackageNames.equals(state.providerPackageNames); } @Override public int hashCode() { - return Objects.hash(enabled, properties, providerPackageNames); + return Objects.hash(allowed, properties, providerPackageNames); } } @@ -259,10 +259,10 @@ public abstract class AbstractLocationProvider { } /** - * The current enabled state of this provider. + * The current allowed state of this provider. */ - protected boolean isEnabled() { - return mInternalState.get().state.enabled; + protected boolean isAllowed() { + return mInternalState.get().state.allowed; } /** @@ -281,10 +281,10 @@ public abstract class AbstractLocationProvider { } /** - * Call this method to report a change in provider enabled/disabled status. + * Call this method to report a change in provider allowed status. */ - protected void setEnabled(boolean enabled) { - setState(state -> state.withEnabled(enabled)); + protected void setAllowed(boolean allowed) { + setState(state -> state.withAllowed(allowed)); } /** @@ -358,6 +358,19 @@ public abstract class AbstractLocationProvider { protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} /** + * Requests a provider to enable itself for the given user id. + */ + public final void requestSetAllowed(boolean allowed) { + // all calls into the provider must be moved onto the provider thread to prevent deadlock + mExecutor.execute(() -> onRequestSetAllowed(allowed)); + } + + /** + * Always invoked on the provider executor. + */ + protected void onRequestSetAllowed(boolean allowed) {} + + /** * Dumps debug or log information. May be invoked from any thread. */ public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java index bb96e985cf53..e27eb65eccfc 100644 --- a/services/core/java/com/android/server/location/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java @@ -16,6 +16,8 @@ package com.android.server.location; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import android.Manifest; import android.app.PendingIntent; import android.content.Context; @@ -110,6 +112,11 @@ public class ContextHubClientBroker extends IContextHubClient.Stub private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false); /* + * True if the application creating the client has the ACCESS_CONTEXT_HUB permission. + */ + private final boolean mHasAccessContextHubPermission; + + /* * Helper class to manage registered PendingIntent requests from the client. */ private class PendingIntentRequest { @@ -166,6 +173,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mCallbackInterface = callback; mPendingIntentRequest = new PendingIntentRequest(); mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); + + mHasAccessContextHubPermission = context.checkCallingPermission( + Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED; } /* package */ ContextHubClientBroker( @@ -179,6 +189,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mHostEndPointId = hostEndPointId; mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId); mPackage = pendingIntent.getCreatorPackage(); + + mHasAccessContextHubPermission = context.checkCallingPermission( + Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED; } /** @@ -416,10 +429,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub */ private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) { try { + String requiredPermission = mHasAccessContextHubPermission + ? Manifest.permission.ACCESS_CONTEXT_HUB + : Manifest.permission.LOCATION_HARDWARE; pendingIntent.send( mContext, 0 /* code */, intent, null /* onFinished */, null /* Handler */, - Manifest.permission.LOCATION_HARDWARE /* requiredPermission */, - null /* options */); + requiredPermission, null /* options */); } catch (PendingIntent.CanceledException e) { mIsPendingIntentCancelled.set(true); // The PendingIntent is no longer valid diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java index 033437a53891..76cd9ceaf7c4 100644 --- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java +++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java @@ -16,6 +16,8 @@ package com.android.server.location; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import android.Manifest; import android.content.Context; import android.hardware.contexthub.V1_0.ContextHub; @@ -30,11 +32,10 @@ import android.hardware.location.NanoAppMessage; import android.hardware.location.NanoAppState; import android.util.Log; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.ArrayList; /** * A class encapsulating helper functions used by the ContextHubService class @@ -42,8 +43,7 @@ import java.util.ArrayList; /* package */ class ContextHubServiceUtil { private static final String TAG = "ContextHubServiceUtil"; private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE; - private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '" - + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware"; + private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB; /** * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an @@ -200,7 +200,11 @@ import java.util.ArrayList; */ /* package */ static void checkPermissions(Context context) { - context.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE); + if (context.checkCallingPermission(HARDWARE_PERMISSION) != PERMISSION_GRANTED + && context.checkCallingPermission(CONTEXT_HUB_PERMISSION) != PERMISSION_GRANTED) { + throw new SecurityException( + "LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permission required to use Context Hub"); + } } /** diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 15cf190952d1..306e1e3afcd7 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -729,7 +729,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements }, UserHandle.USER_ALL); setProperties(PROPERTIES); - setEnabled(true); + setAllowed(true); } /** diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 805b018a8f45..cf299fe9bb2a 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -97,8 +97,8 @@ public class LocationProviderProxy extends AbstractLocationProvider { // executed on binder thread @Override - public void onSetEnabled(boolean enabled) { - setEnabled(enabled); + public void onSetAllowed(boolean allowed) { + setAllowed(allowed); } // executed on binder thread @@ -169,6 +169,14 @@ public class LocationProviderProxy extends AbstractLocationProvider { } @Override + public void onRequestSetAllowed(boolean allowed) { + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + service.requestSetAllowed(allowed); + }); + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("service=" + mServiceWatcher); } diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 60c9fc12c201..bcec8b12b371 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -42,9 +42,9 @@ public class MockProvider extends AbstractLocationProvider { setProperties(properties); } - /** Sets the enabled state of this mock provider. */ - public void setProviderEnabled(boolean enabled) { - setEnabled(enabled); + /** Sets the allowed state of this mock provider. */ + public void setProviderAllowed(boolean allowed) { + setAllowed(allowed); } /** Sets the location to report for this mock provider. */ @@ -56,10 +56,15 @@ public class MockProvider extends AbstractLocationProvider { } @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("last mock location=" + mLocation); + public void onSetRequest(ProviderRequest request) {} + + @Override + protected void onRequestSetAllowed(boolean allowed) { + setAllowed(allowed); } @Override - public void onSetRequest(ProviderRequest request) {} + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("last mock location=" + mLocation); + } } diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java index f50dfe7edbb7..18615f87609f 100644 --- a/services/core/java/com/android/server/location/MockableLocationProvider.java +++ b/services/core/java/com/android/server/location/MockableLocationProvider.java @@ -170,13 +170,13 @@ public class MockableLocationProvider extends AbstractLocationProvider { } /** - * Sets the mock provider implementation's enabled state. Will throw an exception if the mock + * Sets the mock provider implementation's allowed state. Will throw an exception if the mock * provider is not currently the active implementation. */ - public void setMockProviderEnabled(boolean enabled) { + public void setMockProviderAllowed(boolean allowed) { synchronized (mOwnerLock) { Preconditions.checkState(isMock()); - mMockProvider.setProviderEnabled(enabled); + mMockProvider.setProviderAllowed(allowed); } } /** diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index b33877069d70..ef157a39fa28 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -56,7 +56,7 @@ public class PassiveProvider extends AbstractLocationProvider { mReportLocation = false; setProperties(PROPERTIES); - setEnabled(true); + setAllowed(true); } @Override diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e92f3ec5a836..eea59ca26f34 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -117,6 +117,7 @@ import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; import android.app.IUriGrantsManager; import android.app.Notification; import android.app.NotificationChannel; @@ -255,6 +256,9 @@ import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import com.android.server.notification.ManagedServices.UserProfiles; +import com.android.server.notification.toast.CustomToastRecord; +import com.android.server.notification.toast.TextToastRecord; +import com.android.server.notification.toast.ToastRecord; import com.android.server.pm.PackageManagerService; import com.android.server.policy.PhoneWindowManager; import com.android.server.statusbar.StatusBarManagerInternal; @@ -295,8 +299,8 @@ import java.util.function.BiConsumer; /** {@hide} */ public class NotificationManagerService extends SystemService { - static final String TAG = "NotificationService"; - static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + public static final String TAG = "NotificationService"; + public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); public static final boolean ENABLE_CHILD_NOTIFICATIONS = SystemProperties.getBoolean("debug.child_notifs", true); @@ -393,6 +397,7 @@ public class NotificationManagerService extends SystemService { private PackageManager mPackageManagerClient; AudioManager mAudioManager; AudioManagerInternal mAudioManagerInternal; + // Can be null for wear @Nullable StatusBarManagerInternal mStatusBar; Vibrator mVibrator; private WindowManagerInternal mWindowManagerInternal; @@ -850,49 +855,6 @@ public class NotificationManagerService extends SystemService { out.endDocument(); } - private static final class ToastRecord - { - public final int pid; - public final String pkg; - public final IBinder token; - public final ITransientNotification callback; - public int duration; - public int displayId; - public Binder windowToken; - - ToastRecord(int pid, String pkg, IBinder token, ITransientNotification callback, - int duration, Binder windowToken, int displayId) { - this.pid = pid; - this.pkg = pkg; - this.token = token; - this.callback = callback; - this.duration = duration; - this.windowToken = windowToken; - this.displayId = displayId; - } - - void update(int duration) { - this.duration = duration; - } - - void dump(PrintWriter pw, String prefix, DumpFilter filter) { - if (filter != null && !filter.matches(pkg)) return; - pw.println(prefix + this); - } - - @Override - public final String toString() - { - return "ToastRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " pkg=" + pkg - + " token=" + token - + " callback=" + callback - + " duration=" + duration - + "}"; - } - } - @VisibleForTesting final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { @@ -2643,6 +2605,19 @@ public class NotificationManagerService extends SystemService { return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; } + private ToastRecord getToastRecord(int pid, String packageName, IBinder token, + @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration, + Binder windowToken, int displayId, + @Nullable ITransientNotificationCallback textCallback) { + if (callback == null) { + return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration, + windowToken, displayId, textCallback); + } else { + return new CustomToastRecord(this, pid, packageName, token, callback, duration, + windowToken, displayId); + } + } + @VisibleForTesting NotificationManagerInternal getInternalService() { return mInternalService; @@ -2654,28 +2629,30 @@ public class NotificationManagerService extends SystemService { // ============================================================================ @Override - public void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, - int duration, int displayId) { - enqueueToast(pkg, token, callback, duration, displayId, false); + public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, + int displayId, @Nullable ITransientNotificationCallback callback) { + enqueueToast(pkg, token, text, null, duration, displayId, callback); } @Override public void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId) { - enqueueToast(pkg, token, callback, duration, displayId, true); + enqueueToast(pkg, token, null, callback, duration, displayId, null); } - private void enqueueToast(String pkg, IBinder token, ITransientNotification callback, - int duration, int displayId, boolean isCustomToast) { + private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, + @Nullable ITransientNotification callback, int duration, int displayId, + @Nullable ITransientNotificationCallback textCallback) { if (DBG) { - Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration + " displayId=" + displayId); } - if (pkg == null || callback == null || token == null) { - Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback + " token=" - + token); - return ; + if (pkg == null || (text == null && callback == null) + || (text != null && callback != null) || token == null) { + Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback=" + + " token=" + token); + return; } final int callingUid = Binder.getCallingUid(); @@ -2703,7 +2680,7 @@ public class NotificationManagerService extends SystemService { return; } - if (isCustomToast && !appIsForeground && !isSystemToast) { + if (callback != null && !appIsForeground && !isSystemToast) { boolean block; try { block = mPlatformCompat.isChangeEnabledByPackageName( @@ -2745,28 +2722,28 @@ public class NotificationManagerService extends SystemService { int count = 0; final int N = mToastQueue.size(); for (int i=0; i<N; i++) { - final ToastRecord r = mToastQueue.get(i); - if (r.pkg.equals(pkg)) { - count++; - if (count >= MAX_PACKAGE_NOTIFICATIONS) { - Slog.e(TAG, "Package has already posted " + count + final ToastRecord r = mToastQueue.get(i); + if (r.pkg.equals(pkg)) { + count++; + if (count >= MAX_PACKAGE_NOTIFICATIONS) { + Slog.e(TAG, "Package has already posted " + count + " toasts. Not showing more. Package=" + pkg); - return; - } - } + return; + } + } } } Binder windowToken = new Binder(); mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId); - record = new ToastRecord(callingPid, pkg, token, callback, duration, - windowToken, displayId); + record = getToastRecord(callingPid, pkg, token, text, callback, duration, + windowToken, displayId, textCallback); mToastQueue.add(record); index = mToastQueue.size() - 1; - keepProcessAliveIfNeededLocked(callingPid); + keepProcessAliveForToastIfNeededLocked(callingPid); } // If it's at index 0, it's the current toast. It doesn't matter if it's - // new or just been updated. Call back and tell it to show itself. + // new or just been updated, show it. // If the callback fails, this will remove it from the list, so don't // assume that it's valid after this. if (index == 0) { @@ -6935,40 +6912,22 @@ public class NotificationManagerService extends SystemService { void showNextToastLocked() { ToastRecord record = mToastQueue.get(0); while (record != null) { - if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); - try { - record.callback.show(record.windowToken); + if (record.show()) { scheduleDurationReachedLocked(record); return; - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to show notification " + record.callback - + " in package " + record.pkg); - // remove it from the list and let the process die - int index = mToastQueue.indexOf(record); - if (index >= 0) { - mToastQueue.remove(index); - } - keepProcessAliveIfNeededLocked(record.pid); - if (mToastQueue.size() > 0) { - record = mToastQueue.get(0); - } else { - record = null; - } } + int index = mToastQueue.indexOf(record); + if (index >= 0) { + mToastQueue.remove(index); + } + record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null; } } @GuardedBy("mToastQueue") void cancelToastLocked(int index) { ToastRecord record = mToastQueue.get(index); - try { - record.callback.hide(); - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to hide notification " + record.callback - + " in package " + record.pkg); - // don't worry about this, we're about to remove it from - // the list anyway - } + record.hide(); ToastRecord lastToast = mToastQueue.remove(index); @@ -6981,7 +6940,7 @@ public class NotificationManagerService extends SystemService { // one way or another. scheduleKillTokenTimeout(lastToast); - keepProcessAliveIfNeededLocked(record.pid); + keepProcessAliveForToastIfNeededLocked(record.pid); if (mToastQueue.size() > 0) { // Show the next one. If the callback fails, this will remove // it from the list, so don't assume that the list hasn't changed @@ -7004,7 +6963,7 @@ public class NotificationManagerService extends SystemService { { mHandler.removeCallbacksAndMessages(r); Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); - int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; + int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; // Accessibility users may need longer timeout duration. This api compares original delay // with user's preference and return longer one. It returns original delay if there's no // preference. @@ -7053,13 +7012,21 @@ public class NotificationManagerService extends SystemService { return -1; } + /** + * Adjust process {@code pid} importance according to whether it has toasts in the queue or not. + */ + public void keepProcessAliveForToastIfNeeded(int pid) { + synchronized (mToastQueue) { + keepProcessAliveForToastIfNeededLocked(pid); + } + } + @GuardedBy("mToastQueue") - void keepProcessAliveIfNeededLocked(int pid) - { + private void keepProcessAliveForToastIfNeededLocked(int pid) { int toastCount = 0; // toasts from this pid ArrayList<ToastRecord> list = mToastQueue; - int N = list.size(); - for (int i=0; i<N; i++) { + int n = list.size(); + for (int i = 0; i < n; i++) { ToastRecord r = list.get(i); if (r.pid == pid) { toastCount++; diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java new file mode 100644 index 000000000000..aca6f4853597 --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java @@ -0,0 +1,83 @@ +/* + * 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.toast; + +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.notification.NotificationManagerService.DBG; + +import android.app.ITransientNotification; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.notification.NotificationManagerService; + +/** + * Represents a custom toast, a toast whose view is provided by the app. + */ +public class CustomToastRecord extends ToastRecord { + private static final String TAG = NotificationManagerService.TAG; + + public final ITransientNotification callback; + + public CustomToastRecord( + NotificationManagerService notificationManager, int pid, String packageName, + IBinder token, ITransientNotification callback, int duration, Binder windowToken, + int displayId) { + super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + this.callback = checkNotNull(callback); + } + + @Override + public boolean show() { + if (DBG) { + Slog.d(TAG, "Show pkg=" + pkg + " callback=" + callback); + } + try { + callback.show(windowToken); + return true; + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to show custom toast " + token + " in package " + + pkg); + mNotificationManager.keepProcessAliveForToastIfNeeded(pid); + return false; + } + } + + @Override + public void hide() { + try { + callback.hide(); + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to hide custom toast " + token + " in package " + + pkg); + + } + } + + @Override + public String toString() { + return "CustomToastRecord{" + + Integer.toHexString(System.identityHashCode(this)) + + " token=" + token + + " packageName=" + pkg + + " callback=" + callback + + " duration=" + getDuration() + + "}"; + } +} diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java new file mode 100644 index 000000000000..3c231b445f62 --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java @@ -0,0 +1,84 @@ +/* + * 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.toast; + +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.notification.NotificationManagerService.DBG; + +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; +import android.os.Binder; +import android.os.IBinder; +import android.util.Slog; + +import com.android.server.notification.NotificationManagerService; +import com.android.server.statusbar.StatusBarManagerInternal; + +/** + * Represents a text toast, a toast rendered by the system that contains only text. + */ +public class TextToastRecord extends ToastRecord { + private static final String TAG = NotificationManagerService.TAG; + + public final CharSequence text; + @Nullable + private final StatusBarManagerInternal mStatusBar; + @Nullable + private final ITransientNotificationCallback mCallback; + + public TextToastRecord(NotificationManagerService notificationManager, + @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName, + IBinder token, CharSequence text, int duration, Binder windowToken, int displayId, + @Nullable ITransientNotificationCallback callback) { + super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + mStatusBar = statusBarManager; + mCallback = callback; + this.text = checkNotNull(text); + } + + @Override + public boolean show() { + if (DBG) { + Slog.d(TAG, "Show pkg=" + pkg + " text=" + text); + } + if (mStatusBar == null) { + Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg); + return false; + } + mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback); + return true; + } + + @Override + public void hide() { + // If it's null, show() would have returned false + checkNotNull(mStatusBar, "Cannot hide toast that wasn't shown"); + + mStatusBar.hideToast(pkg, token); + } + + @Override + public String toString() { + return "TextToastRecord{" + + Integer.toHexString(System.identityHashCode(this)) + + " token=" + token + + " packageName=" + pkg + + " text=" + text + + " duration=" + getDuration() + + "}"; + } +} diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java new file mode 100644 index 000000000000..ef75a6f5dd7b --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java @@ -0,0 +1,88 @@ +/* + * 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.toast; + +import android.os.Binder; +import android.os.IBinder; + +import com.android.server.notification.NotificationManagerService; +import com.android.server.notification.NotificationManagerService.DumpFilter; + +import java.io.PrintWriter; + +/** + * Represents a toast, a transient notification. + */ +public abstract class ToastRecord { + public final int pid; + public final String pkg; + public final IBinder token; + public final int displayId; + public final Binder windowToken; + protected final NotificationManagerService mNotificationManager; + private int mDuration; + + protected ToastRecord( + NotificationManagerService notificationManager, + int pid, String pkg, IBinder token, int duration, + Binder windowToken, int displayId) { + this.mNotificationManager = notificationManager; + this.pid = pid; + this.pkg = pkg; + this.token = token; + this.windowToken = windowToken; + this.displayId = displayId; + mDuration = duration; + } + + /** + * This method is responsible for showing the toast represented by this object. + * + * @return True if it was successfully shown. + */ + public abstract boolean show(); + + /** + * This method is responsible for hiding the toast represented by this object. + */ + public abstract void hide(); + + /** + * Returns the duration of this toast, which can be {@link android.widget.Toast#LENGTH_SHORT} + * or {@link android.widget.Toast#LENGTH_LONG}. + */ + public int getDuration() { + return mDuration; + } + + /** + * Updates toast duration. + */ + public void update(int duration) { + mDuration = duration; + } + + /** + * Dumps a textual representation of this object. + */ + public void dump(PrintWriter pw, String prefix, DumpFilter filter) { + if (filter != null && !filter.matches(pkg)) { + return; + } + pw.println(prefix + this); + } +} diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index ac3bf9ad5d8a..0a9f923ac817 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -43,6 +43,9 @@ import java.util.Map; */ public class OverlayActorEnforcer { + // By default, the reason is not logged to prevent leaks of why it failed + private static final boolean DEBUG_REASON = false; + private final VerifyCallback mVerifyCallback; /** @@ -92,7 +95,7 @@ public class OverlayActorEnforcer { throw new SecurityException("UID" + callingUid + " is not allowed to call " + methodName + " for " + (TextUtils.isEmpty(targetOverlayableName) ? "" : (targetOverlayableName + " in ")) - + overlayInfo.targetPackageName + " because " + actorState + + overlayInfo.targetPackageName + (DEBUG_REASON ? (" because " + actorState) : "") ); } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 9dff7754c4f3..6e7e5d884a4a 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -662,7 +662,7 @@ public class AppsFilter { String description, Throwable throwable) { Slog.wtf(TAG, "interaction: " + callingPkgSetting - + " -> " + targetPkgSetting.name + " " + + " -> " + targetPkgSetting + " " + description, throwable); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 10f46fd808c8..c17ad1119631 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -402,10 +402,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } finally { IoUtils.closeQuietly(fis); } - // After all of the sessions were loaded, they are ready to be sealed and validated + // After reboot housekeeping. for (int i = 0; i < mSessions.size(); ++i) { PackageInstallerSession session = mSessions.valueAt(i); - session.sealAndValidateIfNecessary(); + session.onAfterSessionRead(); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ef2873358cd4..a22332648e0b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -372,7 +372,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(b/146080380): merge file list with Callback installation. private IncrementalFileStorages mIncrementalFileStorages; - private static final FileFilter sAddedFilter = new FileFilter() { + private static final String[] EMPTY_STRING_ARRAY = new String[]{}; + + private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { // Installers can't stage directories, so it's fine to ignore @@ -384,6 +386,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return true; } }; + private static final FileFilter sAddedFilter = new FileFilter() { + @Override + public boolean accept(File file) { + // Installers can't stage directories, so it's fine to ignore + // entries like "lost+found". + if (file.isDirectory()) return false; + if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false; + return true; + } + }; private static final FileFilter sRemovedFilter = new FileFilter() { @Override public boolean accept(File file) { @@ -713,7 +725,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private String[] getNamesLocked() { if (!isDataLoaderInstallation()) { - return stageDir.list(); + String[] result = stageDir.list(); + if (result == null) { + result = EMPTY_STRING_ARRAY; + } + return result; } return mFiles.stream().map(fileInfo -> fileInfo.name).toArray(String[]::new); } @@ -724,9 +740,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @GuardedBy("mLock") - private File[] getAddedFilesLocked() { + private File[] getAddedApksLocked() { String[] names = getNamesLocked(); - return filterFiles(stageDir, names, sAddedFilter); + return filterFiles(stageDir, names, sAddedApkFilter); } @GuardedBy("mLock") @@ -1339,7 +1355,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { prepareDataLoader(); - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { validateApexInstallLocked(); } else { validateApkInstallLocked(pkgInfo); @@ -1370,15 +1386,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** - * If session should be sealed, then it's sealed to prevent further modification - * and then it's validated. + * If session should be sealed, then it's sealed to prevent further modification. + * If the session can't be sealed then it's destroyed. * - * If the session was sealed but something went wrong then it's destroyed. + * Additionally for staged APEX sessions read+validate the package and populate req'd fields. * * <p> This is meant to be called after all of the sessions are loaded and added to * PackageInstallerService */ - void sealAndValidateIfNecessary() { + void onAfterSessionRead() { synchronized (mLock) { if (!mShouldBeSealed || isStagedAndInTerminalState()) { return; @@ -1387,9 +1403,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { List<PackageInstallerSession> childSessions = getChildSessions(); synchronized (mLock) { try { - sealAndValidateLocked(childSessions); - } catch (StreamingException e) { - Slog.e(TAG, "Streaming failed", e); + sealLocked(childSessions); + + if (isApexInstallation()) { + // APEX installations rely on certain fields to be populated after reboot. + // E.g. mPackageName. + validateApexInstallLocked(); + } } catch (PackageManagerException e) { Slog.e(TAG, "Package not valid", e); } @@ -1465,7 +1485,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { destroyInternal(); dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "APEX packages can only be installed using staged sessions.", null); @@ -1549,7 +1569,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final IPackageInstallObserver2 localObserver; - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { localObserver = null; } else { if (!params.isMultiPackage) { @@ -1684,6 +1704,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** + * Returns true if the session is installing an APEX package. + */ + private boolean isApexInstallation() { + return (params.installFlags & PackageManager.INSTALL_APEX) != 0; + } + + /** * Validate apex install. * <p> * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for @@ -1692,7 +1719,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void validateApexInstallLocked() throws PackageManagerException { - final File[] addedFiles = getAddedFilesLocked(); + final File[] addedFiles = getAddedApksLocked(); if (ArrayUtils.isEmpty(addedFiles)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } @@ -1780,7 +1807,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - final File[] addedFiles = getAddedFilesLocked(); + final File[] addedFiles = getAddedApksLocked(); if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca4ae0277aaf..de6b7d5af397 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -27,6 +27,7 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_DEFAULT; import static android.content.Intent.CATEGORY_HOME; +import static android.content.Intent.EXTRA_LONG_VERSION_CODE; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_VERSION_CODE; import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509; @@ -124,8 +125,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ApplicationPackageManager; import android.app.AppOpsManager; +import android.app.ApplicationPackageManager; import android.app.BroadcastOptions; import android.app.IActivityManager; import android.app.ResourcesManager; @@ -386,6 +387,7 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -2867,23 +2869,34 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } + final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; + final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; + + PackageParser packageParser = new PackageParser(); + packageParser.setSeparateProcesses(mSeparateProcesses); + packageParser.setOnlyCoreApps(mOnlyCore); + packageParser.setDisplayMetrics(mMetrics); + packageParser.setCacheDir(mCacheDir); + packageParser.setCallback(mPackageParserCallback); + + ExecutorService executorService = ParallelPackageParser.makeExecutorService(); // Collect vendor/product/system_ext overlay packages. (Do this before scanning // any apps.) // For security and version matching reason, only consider overlay packages if they // reside in the right directory. - final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; - final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM; for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) { final SystemPartition partition = mDirsToScanAsSystem.get(i); if (partition.overlayFolder == null) { continue; } scanDirTracedLI(partition.overlayFolder, systemParseFlags, - systemScanFlags | partition.scanFlag, 0); + systemScanFlags | partition.scanFlag, 0, + packageParser, executorService); } scanDirTracedLI(frameworkDir, systemParseFlags, - systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0); + systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0, + packageParser, executorService); if (!mPackages.containsKey("android")) { throw new IllegalStateException( "Failed to load frameworks package; check log for warnings"); @@ -2892,10 +2905,12 @@ public class PackageManagerService extends IPackageManager.Stub final SystemPartition partition = mDirsToScanAsSystem.get(i); if (partition.privAppFolder != null) { scanDirTracedLI(partition.privAppFolder, systemParseFlags, - systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0); + systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0, + packageParser, executorService); } scanDirTracedLI(partition.appFolder, systemParseFlags, - systemScanFlags | partition.scanFlag, 0); + systemScanFlags | partition.scanFlag, 0, + packageParser, executorService); } @@ -2999,8 +3014,18 @@ public class PackageManagerService extends IPackageManager.Stub if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); - scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); + scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, + packageParser, executorService); + + } + + List<Runnable> unfinishedTasks = executorService.shutdownNow(); + if (!unfinishedTasks.isEmpty()) { + throw new IllegalStateException("Not all tasks finished before calling close: " + + unfinishedTasks); + } + if (!mOnlyCore) { // Remove disable package settings for updated system apps that were // removed via an OTA. If the update is no longer present, remove the // app completely. Otherwise, revoke their system privileges. @@ -4554,7 +4579,10 @@ public class PackageManagerService extends IPackageManager.Stub flags = updateFlagsForPackage(flags, userId); mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid"); + return getPackageUidInternal(packageName, flags, userId, callingUid); + } + private int getPackageUidInternal(String packageName, int flags, int userId, int callingUid) { // reader synchronized (mLock) { final AndroidPackage p = mPackages.get(packageName); @@ -8574,16 +8602,18 @@ public class PackageManagerService extends IPackageManager.Stub return finalList; } - private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) { + private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, + long currentTime, PackageParser packageParser, ExecutorService executorService) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]"); try { - scanDirLI(scanDir, parseFlags, scanFlags, currentTime); + scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } - private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) { + private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime, + PackageParser packageParser, ExecutorService executorService) { final File[] files = scanDir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + scanDir); @@ -8594,58 +8624,58 @@ public class PackageManagerService extends IPackageManager.Stub Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags + " flags=0x" + Integer.toHexString(parseFlags)); } - try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser( - mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, - mPackageParserCallback)) { - // Submit files for parsing in parallel - int fileCount = 0; - for (File file : files) { - final boolean isPackage = (isApkFile(file) || file.isDirectory()) - && !PackageInstallerService.isStageName(file.getName()); - if (!isPackage) { - // Ignore entries which are not packages - continue; - } - parallelPackageParser.submit(file, parseFlags); - fileCount++; + + ParallelPackageParser parallelPackageParser = + new ParallelPackageParser(packageParser, executorService); + + // Submit files for parsing in parallel + int fileCount = 0; + for (File file : files) { + final boolean isPackage = (isApkFile(file) || file.isDirectory()) + && !PackageInstallerService.isStageName(file.getName()); + if (!isPackage) { + // Ignore entries which are not packages + continue; } + parallelPackageParser.submit(file, parseFlags); + fileCount++; + } - // Process results one by one - for (; fileCount > 0; fileCount--) { - ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); - Throwable throwable = parseResult.throwable; - int errorCode = PackageManager.INSTALL_SUCCEEDED; + // Process results one by one + for (; fileCount > 0; fileCount--) { + ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); + Throwable throwable = parseResult.throwable; + int errorCode = PackageManager.INSTALL_SUCCEEDED; - if (throwable == null) { - // TODO(toddke): move lower in the scan chain - // Static shared libraries have synthetic package names - if (parseResult.parsedPackage.isStaticSharedLibrary()) { - renameStaticSharedLibraryPackage(parseResult.parsedPackage); - } - try { - addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, - currentTime, null); - } catch (PackageManagerException e) { - errorCode = e.error; - Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage()); - } - } else if (throwable instanceof PackageParserException) { - PackageParserException e = (PackageParserException) - throwable; + if (throwable == null) { + // TODO(toddke): move lower in the scan chain + // Static shared libraries have synthetic package names + if (parseResult.parsedPackage.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parseResult.parsedPackage); + } + try { + addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, + currentTime, null); + } catch (PackageManagerException e) { errorCode = e.error; - Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage()); - } else { - throw new IllegalStateException("Unexpected exception occurred while parsing " - + parseResult.scanFile, throwable); + Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage()); } + } else if (throwable instanceof PackageParserException) { + PackageParserException e = (PackageParserException) + throwable; + errorCode = e.error; + Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage()); + } else { + throw new IllegalStateException("Unexpected exception occurred while parsing " + + parseResult.scanFile, throwable); + } - // Delete invalid userdata apps - if ((scanFlags & SCAN_AS_SYSTEM) == 0 && - errorCode != PackageManager.INSTALL_SUCCEEDED) { - logCriticalInfo(Log.WARN, - "Deleting invalid package at " + parseResult.scanFile); - removeCodePathLI(parseResult.scanFile); - } + // Delete invalid userdata apps + if ((scanFlags & SCAN_AS_SYSTEM) == 0 + && errorCode != PackageManager.INSTALL_SUCCEEDED) { + logCriticalInfo(Log.WARN, + "Deleting invalid package at " + parseResult.scanFile); + removeCodePathLI(parseResult.scanFile); } } } @@ -14375,6 +14405,7 @@ public class PackageManagerService extends IPackageManager.Stub integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId); integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName); integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode); + integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode()); populateInstallerExtras(integrityVerification); // send to integrity component only. @@ -20211,8 +20242,8 @@ public class PackageManagerService extends IPackageManager.Stub // Disable any carrier apps. We do this very early in boot to prevent the apps from being // disabled after already being started. - CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, - mPermissionManagerService, UserHandle.USER_SYSTEM, mContext); + CarrierAppUtils.disableCarrierAppsUntilPrivileged( + mContext.getOpPackageName(), UserHandle.USER_SYSTEM, mContext); disableSkuSpecificApps(); @@ -23098,6 +23129,12 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public int getPackageUidInternal(String packageName, int flags, int userId) { + return PackageManagerService.this + .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID); + } + + @Override public ApplicationInfo getApplicationInfo( String packageName, int flags, int filterCallingUid, int userId) { return PackageManagerService.this diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java index a5065145cafd..448dad026e16 100644 --- a/services/core/java/com/android/server/pm/ParallelPackageParser.java +++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java @@ -22,13 +22,11 @@ import android.content.pm.PackageParser; import android.content.pm.parsing.ParsedPackage; import android.os.Process; import android.os.Trace; -import android.util.DisplayMetrics; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ConcurrentUtils; import java.io.File; -import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; @@ -38,30 +36,27 @@ import java.util.concurrent.ExecutorService; * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}. * At any time, at most {@link #QUEUE_CAPACITY} results are kept in RAM</p> */ -class ParallelPackageParser implements AutoCloseable { +class ParallelPackageParser { - private static final int QUEUE_CAPACITY = 10; + private static final int QUEUE_CAPACITY = 30; private static final int MAX_THREADS = 4; - private final String[] mSeparateProcesses; - private final boolean mOnlyCore; - private final DisplayMetrics mMetrics; - private final File mCacheDir; - private final PackageParser.Callback mPackageParserCallback; private volatile String mInterruptedInThread; private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY); - private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS, - "package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND); + static ExecutorService makeExecutorService() { + return ConcurrentUtils.newFixedThreadPool(MAX_THREADS, "package-parsing-thread", + Process.THREAD_PRIORITY_FOREGROUND); + } + + private final PackageParser mPackageParser; + + private final ExecutorService mExecutorService; - ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps, - DisplayMetrics metrics, File cacheDir, PackageParser.Callback callback) { - mSeparateProcesses = separateProcesses; - mOnlyCore = onlyCoreApps; - mMetrics = metrics; - mCacheDir = cacheDir; - mPackageParserCallback = callback; + ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + mPackageParser = packageParser; + mExecutorService = executorService; } static class ParseResult { @@ -104,18 +99,12 @@ class ParallelPackageParser implements AutoCloseable { * @param parseFlags parse flags */ public void submit(File scanFile, int parseFlags) { - mService.submit(() -> { + mExecutorService.submit(() -> { ParseResult pr = new ParseResult(); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]"); try { - PackageParser pp = new PackageParser(); - pp.setSeparateProcesses(mSeparateProcesses); - pp.setOnlyCoreApps(mOnlyCore); - pp.setDisplayMetrics(mMetrics); - pp.setCacheDir(mCacheDir); - pp.setCallback(mPackageParserCallback); pr.scanFile = scanFile; - pr.parsedPackage = parsePackage(pp, scanFile, parseFlags); + pr.parsedPackage = parsePackage(scanFile, parseFlags); } catch (Throwable e) { pr.throwable = e; } finally { @@ -134,17 +123,8 @@ class ParallelPackageParser implements AutoCloseable { } @VisibleForTesting - protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, - int parseFlags) throws PackageParser.PackageParserException { - return packageParser.parseParsedPackage(scanFile, parseFlags, true); - } - - @Override - public void close() { - List<Runnable> unfinishedTasks = mService.shutdownNow(); - if (!unfinishedTasks.isEmpty()) { - throw new IllegalStateException("Not all tasks finished before calling close: " - + unfinishedTasks); - } + protected ParsedPackage parsePackage(File scanFile, int parseFlags) + throws PackageParser.PackageParserException { + return mPackageParser.parseParsedPackage(scanFile, parseFlags, true); } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c3e7f62e4f31..da0d82047cbe 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -333,8 +333,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } - private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200; - /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */ static final int WAITING_FOR_DRAWN_TIMEOUT = 1000; @@ -487,7 +485,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mPendingKeyguardOccluded; private boolean mKeyguardOccludedChanged; - private boolean mNotifyUserActivity; SleepToken mScreenOffSleepToken; volatile boolean mKeyguardOccluded; @@ -627,8 +624,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_LAUNCH_ASSIST = 23; private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 24; private static final int MSG_POWER_VERY_LONG_PRESS = 25; - private static final int MSG_NOTIFY_USER_ACTIVITY = 26; - private static final int MSG_RINGER_TOGGLE_CHORD = 27; + private static final int MSG_RINGER_TOGGLE_CHORD = 26; private class PolicyHandler extends Handler { @Override @@ -708,13 +704,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_HANDLE_ALL_APPS: launchAllAppsAction(); break; - case MSG_NOTIFY_USER_ACTIVITY: - removeMessages(MSG_NOTIFY_USER_ACTIVITY); - Intent intent = new Intent(ACTION_USER_ACTIVITY_NOTIFICATION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, - android.Manifest.permission.USER_ACTIVITY); - break; case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); break; @@ -4892,13 +4881,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE); } - @Override - public void requestUserActivityNotification() { - if (!mNotifyUserActivity && !mHandler.hasMessages(MSG_NOTIFY_USER_ACTIVITY)) { - mNotifyUserActivity = true; - } - } - /** {@inheritDoc} */ @Override public void userActivity() { @@ -4920,12 +4902,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } - - if (mDefaultDisplayPolicy.isAwake() && mNotifyUserActivity) { - mHandler.sendEmptyMessageDelayed(MSG_NOTIFY_USER_ACTIVITY, - USER_ACTIVITY_NOTIFICATION_DELAY); - mNotifyUserActivity = false; - } } class ScreenLockTimeout implements Runnable { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index c39da5fb0e99..e81214e44aff 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1438,12 +1438,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** - * Requests that the WindowManager sends - * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. - */ - public void requestUserActivityNotification(); - - /** * Registers an IDisplayFoldListener. */ default void registerDisplayFoldListener(IDisplayFoldListener listener) {} diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index 5c0dd9a44dc4..cb583cd42412 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -179,6 +179,13 @@ class Rollback { private final IntArray mTokens = new IntArray(); /** + * Session ids for all packages in the install. For multi-package sessions, this is the list + * of child session ids. For normal sessions, this list is a single element with the normal + * session id. + */ + private final int[] mPackageSessionIds; + + /** * Constructs a new, empty Rollback instance. * * @param rollbackId the id of the rollback. @@ -186,9 +193,10 @@ class Rollback { * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise. * @param userId the user that performed the install with rollback enabled. * @param installerPackageName the installer package name from the original install session. + * @param packageSessionIds the session ids for all packages in the install. */ Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId, - String installerPackageName) { + String installerPackageName, int[] packageSessionIds) { this.info = new RollbackInfo(rollbackId, /* packages */ new ArrayList<>(), /* isStaged */ stagedSessionId != -1, @@ -200,6 +208,12 @@ class Rollback { mStagedSessionId = stagedSessionId; mState = ROLLBACK_STATE_ENABLING; mTimestamp = Instant.now(); + mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0]; + } + + Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId, + String installerPackageName) { + this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null); } /** @@ -217,6 +231,11 @@ class Rollback { mState = state; mApkSessionId = apkSessionId; mRestoreUserDataInProgress = restoreUserDataInProgress; + // TODO(b/120200473): Include this field during persistence. This field will be used to + // decide which rollback to expire when ACTION_PACKAGE_REPLACED is received. Note persisting + // this field is not backward compatible. We won't fix b/120200473 until S to minimize the + // impact. + mPackageSessionIds = new int[0]; } /** @@ -793,6 +812,25 @@ class Rollback { } } + /** + * Returns true if this rollback contains the provided {@code packageSessionId}. + */ + boolean containsSessionId(int packageSessionId) { + for (int id : mPackageSessionIds) { + if (id == packageSessionId) { + return true; + } + } + return false; + } + + /** + * Returns the number of package session ids in this rollback. + */ + int getPackageSessionIdCount() { + return mPackageSessionIds.length; + } + static String rollbackStateToString(@RollbackState int state) { switch (state) { case Rollback.ROLLBACK_STATE_ENABLING: return "enabling"; diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index de48939825e4..4bab22478e6a 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -1238,7 +1238,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // equal to the number of sessions we are installing, to ensure we didn't skip enabling // of any sessions. If we successfully enable an apex, then we can assume we enabled // rollback for the embedded apk-in-apex, if any. - if (rollback.getPackageCount(0 /*flags*/) != newRollback.getPackageSessionIdCount()) { + // TODO: add a helper instead of exposing 2 methods from Rollback + if (rollback.getPackageCount(0 /*flags*/) != rollback.getPackageSessionIdCount()) { Slog.e(TAG, "Failed to enable rollback for all packages in session."); rollback.delete(mAppDataRollbackHelper); return null; @@ -1343,13 +1344,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { public final Rollback rollback; /** - * Session ids for all packages in the install. For multi-package sessions, this is the list - * of child session ids. For normal sessions, this list is a single element with the normal - * session id. - */ - private final int[] mPackageSessionIds; - - /** * The number of sessions in the install which are notified with success by * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}. * This NewRollback will be enabled only after all child sessions finished with success. @@ -1359,28 +1353,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final Object mNewRollbackLock = new Object(); - NewRollback(Rollback rollback, int[] packageSessionIds) { + NewRollback(Rollback rollback) { this.rollback = rollback; - this.mPackageSessionIds = packageSessionIds; - } - - /** - * Returns true if this NewRollback contains the provided {@code packageSessionId}. - */ - boolean containsSessionId(int packageSessionId) { - for (int id : mPackageSessionIds) { - if (id == packageSessionId) { - return true; - } - } - return false; - } - - /** - * Returns the number of package session ids in this NewRollback. - */ - int getPackageSessionIdCount() { - return mPackageSessionIds.length; } /** @@ -1390,7 +1364,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { */ boolean notifySessionWithSuccess() { synchronized (mNewRollbackLock) { - return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length; + return ++mNumPackageSessionsWithSuccess == rollback.getPackageSessionIdCount(); } } } @@ -1414,14 +1388,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { + " user=" + userId + " installer=" + installerPackageName); } - if (parentSession.isStaged()) { - rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId, - installerPackageName); - } else { - rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId, - installerPackageName); - } - int[] packageSessionIds; if (parentSession.isMultiPackage()) { packageSessionIds = parentSession.getChildSessionIds(); @@ -1429,7 +1395,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { packageSessionIds = new int[]{parentSessionId}; } - return new NewRollback(rollback, packageSessionIds); + if (parentSession.isStaged()) { + rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId, + installerPackageName, packageSessionIds); + } else { + rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId, + installerPackageName, packageSessionIds); + } + + return new NewRollback(rollback); } /** @@ -1443,7 +1417,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // We expect mNewRollbacks to be a very small list; linear search // should be plenty fast. for (NewRollback newRollback: mNewRollbacks) { - if (newRollback.containsSessionId(packageSessionId)) { + if (newRollback.rollback.containsSessionId(packageSessionId)) { return newRollback; } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index bbcd0def05a8..4f894821db27 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -204,6 +204,13 @@ class RollbackStore { return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName); } + Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName, + int[] packageSessionIds) { + File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); + return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName, + packageSessionIds); + } + /** * Creates a new Rollback instance for a staged rollback with * backupDir assigned. @@ -215,6 +222,17 @@ class RollbackStore { } /** + * TODO: Now we have 4 factory methods for creating Rollback objects which is verbose and + * cumbersome. Need to merge them for simplicity. + */ + Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId, + String installerPackageName, int[] packageSessionIds) { + File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); + return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, + packageSessionIds); + } + + /** * Creates a backup copy of an apk or apex for a package. * For packages containing splits, this method should be called for each * of the package's split apks in addition to the base apk. 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 39d1a51c01de..92e5a01fc796 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -1268,6 +1268,7 @@ public class StatsPullAtomService extends SystemService { continue; } StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) .writeInt(managedProcess.uid) .writeString(managedProcess.processName) .writeInt(managedProcess.pid) diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 95ffd8fe43d8..d88dccb9afeb 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -16,7 +16,10 @@ package com.android.server.statusbar; +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; import android.os.Bundle; +import android.os.IBinder; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; @@ -123,4 +126,15 @@ public interface StatusBarManagerInternal { /** @see com.android.internal.statusbar.IStatusBar#abortTransient */ void abortTransient(int displayId, @InternalInsetsType int[] types); + + /** + * @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence, + * IBinder, int, ITransientNotificationCallback) + */ + void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback textCallback); + + /** @see com.android.internal.statusbar.IStatusBar#hideToast(String, IBinder) */ + void hideToast(String packageName, IBinder token); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 870c81fb5dc2..3f7d373c1848 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.Nullable; import android.app.ActivityThread; +import android.app.ITransientNotificationCallback; import android.app.Notification; import android.app.StatusBarManager; import android.content.ComponentName; @@ -500,6 +501,26 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } catch (RemoteException ex) { } } } + + @Override + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback callback) { + if (mBar != null) { + try { + mBar.showToast(packageName, token, text, windowToken, duration, callback); + } catch (RemoteException ex) { } + } + } + + @Override + public void hideToast(String packageName, IBinder token) { + if (mBar != null) { + try { + mBar.hideToast(packageName, token); + } catch (RemoteException ex) { } + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 0abe68f270f3..8130546e2699 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.PatternMatcher; import android.os.Process; @@ -34,6 +35,7 @@ import android.webkit.WebViewProviderInfo; import android.webkit.WebViewProviderResponse; import com.android.internal.util.DumpUtils; +import com.android.server.LocalServices; import com.android.server.SystemService; import java.io.FileDescriptor; @@ -191,7 +193,26 @@ public class WebViewUpdateService extends SystemService { throw new IllegalStateException("Cannot create a WebView from the SystemServer"); } - return WebViewUpdateService.this.mImpl.waitForAndGetProvider(); + final WebViewProviderResponse webViewProviderResponse = + WebViewUpdateService.this.mImpl.waitForAndGetProvider(); + if (webViewProviderResponse.packageInfo != null) { + grantVisibilityToCaller( + webViewProviderResponse.packageInfo.packageName, Binder.getCallingUid()); + } + return webViewProviderResponse; + } + + /** + * Grants app visibility of the webViewPackageName to the currently bound caller. + * @param webViewPackageName + */ + private void grantVisibilityToCaller(String webViewPackageName, int callingUid) { + final PackageManagerInternal pmInternal = LocalServices.getService( + PackageManagerInternal.class); + final int webviewUid = pmInternal.getPackageUidInternal( + webViewPackageName, 0, UserHandle.getUserId(callingUid)); + pmInternal.grantImplicitAccess(UserHandle.getUserId(callingUid), null, webviewUid, + UserHandle.getAppId(callingUid)); } /** @@ -231,13 +252,18 @@ public class WebViewUpdateService extends SystemService { @Override // Binder call public String getCurrentWebViewPackageName() { - PackageInfo pi = WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + PackageInfo pi = getCurrentWebViewPackage(); return pi == null ? null : pi.packageName; } @Override // Binder call public PackageInfo getCurrentWebViewPackage() { - return WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + final PackageInfo currentWebViewPackage = + WebViewUpdateService.this.mImpl.getCurrentWebViewPackage(); + if (currentWebViewPackage != null) { + grantVisibilityToCaller(currentWebViewPackage.packageName, Binder.getCallingUid()); + } + return currentWebViewPackage; } @Override // Binder call diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d1c8448f2a4a..33e18c1263ab 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -94,7 +94,6 @@ import static android.os.Build.VERSION_CODES.O; import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.COLOR_MODE_DEFAULT; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; @@ -495,7 +494,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // process that it is hidden. private boolean mLastDeferHidingClient; // If true we will defer setting mClientVisible to false // and reporting to the client that it is hidden. - boolean sleeping; // have we told the activity to sleep? + private boolean mSetToSleep; // have we told the activity to sleep? boolean nowVisible; // is this activity's window visible? boolean mDrawn; // is this activity's window drawn? boolean mClientVisibilityDeferred;// was the visibility change message to client deferred? @@ -613,6 +612,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private boolean mLastContainsShowWhenLockedWindow; private boolean mLastContainsDismissKeyguardWindow; + private boolean mLastContainsTurnScreenOnWindow; /** * A flag to determine if this AR is in the process of closing or entering PIP. This is needed @@ -895,7 +895,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" finishing="); pw.println(finishing); pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); pw.print(" inHistory="); pw.print(inHistory); - pw.print(" sleeping="); pw.print(sleeping); + pw.print(" setToSleep="); pw.print(mSetToSleep); pw.print(" idle="); pw.print(idle); pw.print(" mStartingWindowState="); pw.println(startingWindowStateToString(mStartingWindowState)); @@ -1627,7 +1627,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A requestedVrComponent = (aInfo.requestedVrComponent == null) ? null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); - lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options); + lockTaskLaunchMode = aInfo.lockTaskLaunchMode; + if (info.applicationInfo.isPrivilegedApp() + && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS + || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { + lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; + } if (options != null) { pendingOptions = options; @@ -1635,25 +1640,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (usageReport != null) { appTimeTracker = new AppTimeTracker(usageReport); } - // Gets launch display id from options. It returns INVALID_DISPLAY if not set. - mHandoverLaunchDisplayId = options.getLaunchDisplayId(); - } - } - - static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) { - int lockTaskLaunchMode = aInfo.lockTaskLaunchMode; - if (aInfo.applicationInfo.isPrivilegedApp() - && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS - || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { - lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; - } - if (options != null) { - final boolean useLockTask = options.getLockTaskMode(); + final boolean useLockTask = pendingOptions.getLockTaskMode(); if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) { lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; } + // Gets launch display id from options. It returns INVALID_DISPLAY if not set. + mHandoverLaunchDisplayId = options.getLaunchDisplayId(); } - return lockTaskLaunchMode; } @Override @@ -2661,7 +2654,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Make sure the record is cleaned out of other places. mStackSupervisor.mStoppingActivities.remove(this); - mStackSupervisor.mGoingToSleepActivities.remove(this); final ActivityStack stack = getRootTask(); final DisplayContent display = getDisplay(); @@ -3364,6 +3356,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mLastContainsDismissKeyguardWindow = containsDismissKeyguard; mLastContainsShowWhenLockedWindow = containsShowWhenLocked; + mLastContainsTurnScreenOnWindow = containsTurnScreenOnWindow(); } boolean containsDismissKeyguardWindow() { @@ -4362,6 +4355,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A || state5 == mState; } + /** + * Returns {@code true} if the Activity is in one of the specified states. + */ + boolean isState(ActivityState state1, ActivityState state2, ActivityState state3, + ActivityState state4, ActivityState state5, ActivityState state6) { + return state1 == mState || state2 == mState || state3 == mState || state4 == mState + || state5 == mState || state6 == mState; + } + void destroySurfaces() { destroySurfaces(false /*cleanupOnResume*/); } @@ -4451,20 +4453,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } - // Whether the activity is on the sleeping display. - // TODO(b/129750406): This should be applied for the default display, too. - final boolean isDisplaySleeping = getDisplay().isSleeping() - && getDisplayId() != DEFAULT_DISPLAY; - // Whether this activity is the top activity of this stack. + // Check if the activity is on a sleeping display, and if it can turn it ON. + if (getDisplay().isSleeping()) { + final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn() + || canShowWhenLocked() || containsDismissKeyguardWindow(); + if (!canTurnScreenOn) { + return false; + } + } + + // Now check whether it's really visible depending on Keyguard state, and update + // {@link ActivityStack} internal states. + // Inform the method if this activity is the top activity of this stack, but exclude the + // case where this is the top activity in a pinned stack. final boolean isTop = this == stack.getTopNonFinishingActivity(); - // Exclude the case where this is the top activity in a pinned stack. final boolean isTopNotPinnedStack = stack.isAttached() && stack.getDisplay().isTopNotPinnedStack(stack); - // Now check whether it's really visible depending on Keyguard state, and update - // {@link ActivityStack} internal states. final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this, visibleIgnoringKeyguard, isTop && isTopNotPinnedStack); - return visibleIgnoringDisplayStatus && !isDisplaySleeping; + + return visibleIgnoringDisplayStatus; } boolean shouldBeVisible() { @@ -4496,7 +4504,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A stack.mUndrawnActivitiesBelowTopTranslucent.add(this); } setVisibility(true); - sleeping = false; + mSetToSleep = false; app.postPendingUiCleanMsg(true); if (reportToClient) { mClientVisibilityDeferred = false; @@ -4506,7 +4514,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // The activity may be waiting for stop, but that is no longer appropriate for it. mStackSupervisor.mStoppingActivities.remove(this); - mStackSupervisor.mGoingToSleepActivities.remove(this); } catch (Exception e) { // Just skip on any failure; we'll make it visible when it next restarts. Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e); @@ -5452,25 +5459,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED; } - void setSleeping(boolean _sleeping) { - setSleeping(_sleeping, false); - } - - void setSleeping(boolean _sleeping, boolean force) { - if (!force && sleeping == _sleeping) { - return; - } - if (attachedToProcess()) { - try { - app.getThread().scheduleSleeping(appToken, _sleeping); - if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) { - mStackSupervisor.mGoingToSleepActivities.add(this); - } - sleeping = _sleeping; - } catch (RemoteException e) { - Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e); - } - } + void setSleeping(boolean sleeping) { + mSetToSleep = sleeping; } static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { @@ -7413,7 +7403,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } boolean getTurnScreenOnFlag() { - return mTurnScreenOn; + return mTurnScreenOn || containsTurnScreenOnWindow(); + } + + private boolean containsTurnScreenOnWindow() { + // When we are relaunching, it is possible for us to be unfrozen before our previous + // windows have been added back. Using the cached value ensures that our previous + // showWhenLocked preference is honored until relaunching is complete. + if (isRelaunching()) { + return mLastContainsTurnScreenOnWindow; + } + for (int i = mChildren.size() - 1; i >= 0; i--) { + if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { + return true; + } + } + return false; } /** diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 942be8409db2..663423f8728b 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1263,6 +1263,8 @@ class ActivityStack extends Task implements BoundsAnimationTarget { void awakeFromSleepingLocked() { // Ensure activities are no longer sleeping. forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false)); + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + false /* preserveWindows */); if (mPausingActivity != null) { Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause"); mPausingActivity.activityPaused(true); @@ -1312,13 +1314,6 @@ class ActivityStack extends Task implements BoundsAnimationTarget { mStackSupervisor.scheduleIdle(); shouldSleep = false; } - - if (containsActivityFromStack(mStackSupervisor.mGoingToSleepActivities)) { - // Still need to tell some activities to sleep; can't sleep yet. - if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep " - + mStackSupervisor.mGoingToSleepActivities.size() + " activities"); - shouldSleep = false; - } } if (shouldSleep) { @@ -1329,16 +1324,18 @@ class ActivityStack extends Task implements BoundsAnimationTarget { } void goToSleep() { - // Ensure visibility without updating configuration, as activities are about to sleep. - ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); - - // Make sure any paused or stopped but visible activities are now sleeping. - // This ensures that the activity's onStop() is called. + // Make sure all visible activities are now sleeping. This will update the activity's + // visibility and onStop() will be called. forAllActivities((r) -> { - if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) { + if (r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING, STOPPED)) { r.setSleeping(true); } }); + + // Ensure visibility after updating sleep states without updating configuration, + // as activities are about to be sent to sleep. + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + !PRESERVE_WINDOWS); } private boolean containsActivityFromStack(List<ActivityRecord> rs) { @@ -2040,8 +2037,17 @@ class ActivityStack extends Task implements BoundsAnimationTarget { return false; } - // If we are sleeping, and there is no resumed activity, and the top - // activity is paused, well that is the state we want. + // If we are currently pausing an activity, then don't do anything until that is done. + final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete(); + if (!allPausedComplete) { + if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) { + Slog.v(TAG_PAUSE, "resumeTopActivityLocked: Skip resume: some activity pausing."); + } + return false; + } + + // If we are sleeping, and there is no resumed activity, and the top activity is paused, + // well that is the state we want. if (shouldSleepOrShutDownActivities() && mLastPausedActivity == next && mRootWindowContainer.allPausedActivitiesComplete()) { @@ -2082,8 +2088,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget { // The activity may be waiting for stop, but that is no longer // appropriate for it. mStackSupervisor.mStoppingActivities.remove(next); - mStackSupervisor.mGoingToSleepActivities.remove(next); - next.sleeping = false; + next.setSleeping(false); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); @@ -2352,7 +2357,7 @@ class ActivityStack extends Task implements BoundsAnimationTarget { EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), next.getTask().mTaskId, next.shortComponentName); - next.sleeping = false; + next.setSleeping(false); mAtmService.getAppWarningsLocked().onResumeActivity(next); next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); next.clearOptionsLocked(); @@ -3985,6 +3990,10 @@ class ActivityStack extends Task implements BoundsAnimationTarget { * Used to make room for shadows in the pinned windowing mode. */ int getStackOutset() { + // If we are drawing shadows on the task then don't outset the stack. + if (mWmService.mRenderShadowsInCompositor) { + return 0; + } DisplayContent displayContent = getDisplayContent(); if (inPinnedWindowingMode() && displayContent != null) { final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); @@ -4034,7 +4043,9 @@ class ActivityStack extends Task implements BoundsAnimationTarget { @Override void onDisplayChanged(DisplayContent dc) { super.onDisplayChanged(dc); - updateSurfaceBounds(); + if (isRootTask()) { + updateSurfaceBounds(); + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 2c0f3e65f198..362e781f7fb9 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -285,9 +285,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { * settle down before doing so. It contains ActivityRecord objects. */ final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<>(); - /** List of activities that are in the process of going to sleep. */ - final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<>(); - /** List of activities whose multi-window mode changed that we need to report to the * application */ private final ArrayList<ActivityRecord> mMultiWindowModeChangedActivities = new ArrayList<>(); @@ -881,7 +878,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } mService.getPackageManagerInternalLocked().notifyPackageUse( r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY); - r.sleeping = false; + r.setSleeping(false); r.forceNewConfig = false; mService.getAppWarningsLocked().onStartActivity(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); @@ -1239,7 +1236,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final PackageInfo packageInfo; try { packageInfo = mService.mContext.getPackageManager() - .getPackageInfo(callingPackage, PackageManager.GET_PERMISSIONS); + .getPackageInfoAsUser(callingPackage, PackageManager.GET_PERMISSIONS, + UserHandle.getUserId(callingUid)); } catch (PackageManager.NameNotFoundException e) { Slog.i(TAG, "Cannot find package info for " + callingPackage); return ACTIVITY_RESTRICTION_NONE; @@ -1991,16 +1989,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - void activitySleptLocked(ActivityRecord r) { - mGoingToSleepActivities.remove(r); - final ActivityStack s = r.getRootTask(); - if (s != null) { - s.checkReadyForSleep(); - } else { - checkReadyForSleepLocked(true); - } - } - void checkReadyForSleepLocked(boolean allowDelay) { if (!mService.isSleepingOrShuttingDownLocked()) { // Do not care. @@ -2137,7 +2125,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { void removeHistoryRecords(WindowProcessController app) { removeHistoryRecords(mStoppingActivities, app, "mStoppingActivities"); - removeHistoryRecords(mGoingToSleepActivities, app, "mGoingToSleepActivities"); removeHistoryRecords(mFinishingActivities, app, "mFinishingActivities"); } @@ -2474,7 +2461,10 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { if (r != null) { r.finishRelaunching(); if (r.getRootTask().shouldSleepOrShutDownActivities()) { - r.setSleeping(true, true); + // Activity is always relaunched to either resumed or paused state. If it was + // relaunched while hidden (by keyguard or smth else), it should be stopped. + r.getStack().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + false /* preserveWindows */); } } } diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index d61d29d1084e..2fb0ac5fbeaa 100644 --- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -52,7 +52,6 @@ import android.os.UserHandle; import android.os.UserManager; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.app.BlockedAppActivity; import com.android.internal.app.HarmfulAppWarningActivity; import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; @@ -167,9 +166,6 @@ class ActivityStartInterceptor { // no user action can undo this. return true; } - if (interceptLockTaskModeViolationPackageIfNeeded()) { - return true; - } if (interceptHarmfulAppIfNeeded()) { // If the app has a "harmful app" warning associated with it, we should ask to uninstall // before issuing the work challenge. @@ -178,6 +174,11 @@ class ActivityStartInterceptor { return interceptWorkProfileChallengeIfNeeded(); } + private boolean hasCrossProfileAnimation() { + return mActivityOptions != null + && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS; + } + /** * If the activity option is the {@link ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} one, * defer the animation until the original intent is started. @@ -185,8 +186,7 @@ class ActivityStartInterceptor { * @return the activity option used to start the original intent. */ private Bundle deferCrossProfileAppsAnimationIfNecessary() { - if (mActivityOptions != null - && mActivityOptions.getAnimationType() == ANIM_OPEN_CROSS_PROFILE_APPS) { + if (hasCrossProfileAnimation()) { mActivityOptions = null; return ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(); } @@ -255,28 +255,13 @@ class ActivityStartInterceptor { } final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, suspendingPackage, mUserId); + final Bundle crossProfileOptions = hasCrossProfileAnimation() + ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle() + : null; + final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid, + FLAG_IMMUTABLE); mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage, - suspendingPackage, dialogInfo, deferCrossProfileAppsAnimationIfNecessary(), - mUserId); - mCallingPid = mRealCallingPid; - mCallingUid = mRealCallingUid; - mResolvedType = null; - mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, 0, mRealCallingUid); - mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/); - return true; - } - - private boolean interceptLockTaskModeViolationPackageIfNeeded() { - if (mAInfo == null || mAInfo.applicationInfo == null) { - return false; - } - LockTaskController controller = mService.getLockTaskController(); - String packageName = mAInfo.applicationInfo.packageName; - int lockTaskLaunchMode = ActivityRecord.getLockTaskLaunchMode(mAInfo, mActivityOptions); - if (controller.isActivityAllowed(mUserId, packageName, lockTaskLaunchMode)) { - return false; - } - mIntent = BlockedAppActivity.createIntent(mUserId, mAInfo.applicationInfo.packageName); + suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId); mCallingPid = mRealCallingPid; mCallingUid = mRealCallingUid; mResolvedType = null; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 31b7c688d685..976fbdb36bba 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1043,6 +1043,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public final int startActivities(IApplicationThread caller, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId) { + assertPackageMatchesCallingUid(callingPackage); final String reason = "startActivities"; enforceNotIsolatedCaller(reason); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason); @@ -1062,10 +1063,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { true /*validateIncomingUser*/); } - int startActivityAsUser(IApplicationThread caller, String callingPackage, + private int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { + assertPackageMatchesCallingUid(callingPackage); enforceNotIsolatedCaller("startActivityAsUser"); userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser, @@ -1238,6 +1240,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { + assertPackageMatchesCallingUid(callingPackage); final WaitResult res = new WaitResult(); enforceNotIsolatedCaller("startActivityAndWait"); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), @@ -1263,6 +1266,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public final int startActivityWithConfig(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, Configuration config, Bundle bOptions, int userId) { + assertPackageMatchesCallingUid(callingPackage); enforceNotIsolatedCaller("startActivityWithConfig"); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, "startActivityWithConfig"); @@ -1447,6 +1451,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Intent intent, String resolvedType, IVoiceInteractionSession session, IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { + assertPackageMatchesCallingUid(callingPackage); mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startVoiceActivity()"); if (session == null || interactor == null) { throw new NullPointerException("null session or interactor"); @@ -1470,6 +1475,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public int startAssistantActivity(String callingPackage, int callingPid, int callingUid, Intent intent, String resolvedType, Bundle bOptions, int userId) { + assertPackageMatchesCallingUid(callingPackage); mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()"); userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity"); @@ -1825,21 +1831,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Binder.restoreCallingIdentity(origId); } - public final void activitySlept(IBinder token) { - if (DEBUG_ALL) Slog.v(TAG, "Activity slept: token=" + token); - - final long origId = Binder.clearCallingIdentity(); - - synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.isInStackLocked(token); - if (r != null) { - mStackSupervisor.activitySleptLocked(r); - } - } - - Binder.restoreCallingIdentity(origId); - } - @Override public void setRequestedOrientation(IBinder token, int requestedOrientation) { synchronized (mGlobalLock) { @@ -2391,15 +2382,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { void moveTaskToFrontLocked(@Nullable IApplicationThread appThread, @Nullable String callingPackage, int taskId, int flags, SafeActivityOptions options, boolean fromRecents) { - final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - if (!isSameApp(callingUid, callingPackage)) { - String msg = "Permission Denial: moveTaskToFrontLocked() from pid=" - + Binder.getCallingPid() + " as package " + callingPackage; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } + assertPackageMatchesCallingUid(callingPackage); if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) { SafeActivityOptions.abort(options); return; @@ -2451,7 +2436,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** * Return true if callingUid is system, or packageName belongs to that callingUid. */ - boolean isSameApp(int callingUid, @Nullable String packageName) { + private boolean isSameApp(int callingUid, @Nullable String packageName) { try { if (callingUid != 0 && callingUid != SYSTEM_UID) { if (packageName == null) { @@ -2468,6 +2453,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return true; } + /** + * Checks that the provided package name matches the current calling UID, throws a security + * exception if it doesn't. + */ + void assertPackageMatchesCallingUid(@Nullable String packageName) { + final int callingUid = Binder.getCallingUid(); + if (isSameApp(callingUid, packageName)) { + return; + } + final String msg = "Permission Denial: package=" + packageName + + " does not belong to uid=" + callingUid; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid, int callingPid, int callingUid, String name) { if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) { @@ -3033,6 +3033,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public List<IBinder> getAppTasks(String callingPackage) { int callingUid = Binder.getCallingUid(); + assertPackageMatchesCallingUid(callingPackage); long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -3303,7 +3304,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - private int sanitizeAndApplyChange(ConfigurationContainer container, + private int sanitizeAndApplyChange(WindowContainer container, WindowContainerTransaction.Change change) { if (!(container instanceof Task || container instanceof ActivityStack)) { throw new RuntimeException("Invalid token in task transaction"); @@ -3347,13 +3348,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - private int applyWindowContainerChange(ConfigurationContainer cc, + private int applyWindowContainerChange(WindowContainer wc, WindowContainerTransaction.Change c) { - int effects = sanitizeAndApplyChange(cc, c); + int effects = sanitizeAndApplyChange(wc, c); Rect enterPipBounds = c.getEnterPipBounds(); if (enterPipBounds != null) { - Task tr = (Task) cc; + Task tr = (Task) wc; mStackSupervisor.updatePictureInPictureMode(tr, enterPipBounds, true); } @@ -3378,17 +3379,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { while (entries.hasNext()) { final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); - final ConfigurationContainer cc = - ConfigurationContainer.RemoteToken.fromBinder( - entry.getKey()).getContainer(); - int containerEffect = applyWindowContainerChange(cc, entry.getValue()); + final WindowContainer wc = WindowContainer.RemoteToken.fromBinder( + entry.getKey()).getContainer(); + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect; // Lifecycle changes will trigger ensureConfig for everything. if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - if (cc instanceof WindowContainer) { - haveConfigChanges.add((WindowContainer) cc); - } + haveConfigChanges.add(wc); } } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { @@ -6332,6 +6330,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { SafeActivityOptions options, int userId, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { + assertPackageMatchesCallingUid(callingPackage); synchronized (mGlobalLock) { return getActivityStartController().startActivitiesInPackage(uid, realCallingPid, realCallingUid, callingPackage, intents, resolvedTypes, resultTo, options, @@ -6347,6 +6346,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { int userId, Task inTask, String reason, boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) { + assertPackageMatchesCallingUid(callingPackage); synchronized (mGlobalLock) { return getActivityStartController().startActivityInPackage(uid, realCallingPid, realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho, diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index 357f9e5bec6c..16a75645f9ae 100644 --- a/services/core/java/com/android/server/wm/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -27,7 +27,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.UserHandle; -import android.util.Slog; /** * An implementation of IAppTask, that allows an app to manage its own tasks via @@ -97,12 +96,7 @@ class AppTaskImpl extends IAppTask.Stub { // Will bring task to front if it already has a root activity. final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - if (!mService.isSameApp(callingUid, callingPackage)) { - String msg = "Permission Denial: moveToFront() from pid=" - + Binder.getCallingPid() + " as package " + callingPackage; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } + mService.assertPackageMatchesCallingUid(callingPackage); final long origId = Binder.clearCallingIdentity(); try { synchronized (mService.mGlobalLock) { @@ -134,6 +128,7 @@ class AppTaskImpl extends IAppTask.Stub { public int startActivity(IBinder whoThread, String callingPackage, Intent intent, String resolvedType, Bundle bOptions) { checkCaller(); + mService.assertPackageMatchesCallingUid(callingPackage); int callingUser = UserHandle.getCallingUserId(); Task task; diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 7b23e2d383b6..9bd380a95ad0 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -39,15 +39,11 @@ import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; -import android.os.IBinder; import android.util.proto.ProtoOutputStream; -import android.view.IWindowContainer; -import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -104,12 +100,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { static final int BOUNDS_CHANGE_SIZE = 1 << 1; /** - * Used as a unique, cross-process identifier for this Container. It also serves a minimal - * interface to other processes. - */ - RemoteToken mRemoteToken = null; - - /** * Returns full configuration applied to this configuration container. * This method should be used for getting settings applied in each particular level of the * hierarchy. @@ -629,21 +619,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { return mFullConfiguration.windowConfiguration.isAlwaysOnTop(); } - /** - * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, - * this will not be focusable either. - */ - boolean isFocusable() { - // TODO(split): Move this to WindowContainer once Split-screen is based on a WindowContainer - // like DisplayArea vs. TaskTiles. - ConfigurationContainer parent = getParent(); - return parent == null || parent.isFocusable(); - } - - boolean setFocusable(boolean focusable) { - return false; - } - boolean hasChild() { return getChildCount() > 0; } @@ -654,40 +629,4 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { abstract protected ConfigurationContainer getParent(); - // TODO: Consider moving to WindowContainer once hierarchies and Task/Stack are merged. - static class RemoteToken extends IWindowContainer.Stub { - final WeakReference<ConfigurationContainer> mWeakRef; - - RemoteToken(ConfigurationContainer container) { - mWeakRef = new WeakReference<>(container); - } - - ConfigurationContainer getContainer() { - return mWeakRef.get(); - } - - static RemoteToken fromBinder(IBinder binder) { - return (RemoteToken) binder; - } - - @Override - public SurfaceControl getLeash() { - throw new RuntimeException("Not implemented"); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("RemoteToken{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(' '); - sb.append(mWeakRef.get()); - sb.append('}'); - return sb.toString(); - } - } - - RemoteToken getRemoteToken() { - return mRemoteToken; - } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 825f93cde52b..bf89bab53f30 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2099,6 +2099,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * the above app windows specify orientation, the orientation is computed from the child window * container, e.g. {@link AppWindowToken#getOrientation(int)}. */ + @ScreenOrientation @Override int getOrientation() { final WindowManagerPolicy policy = mWmService.mPolicy; @@ -3116,6 +3117,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + onWindowFocusChanged(oldFocus, newFocus); + int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus); if (imWindowChanged && oldFocus != mInputMethodWindow) { @@ -3158,6 +3161,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return true; } + private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) { + final Task focusedTask = newFocus != null ? newFocus.getTask() : null; + final Task unfocusedTask = oldFocus != null ? oldFocus.getTask() : null; + if (focusedTask == unfocusedTask) { + return; + } + if (focusedTask != null) { + focusedTask.onWindowFocusChanged(true /* hasFocus */); + } + if (unfocusedTask != null) { + unfocusedTask.onWindowFocusChanged(false /* hasFocus */); + } + } + /** * Set the new focused app to this display. * diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index f90f22423a2d..da773143f75c 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -1001,18 +1001,22 @@ public class DisplayRotation { * Given an orientation constant, returns the appropriate surface rotation, taking into account * sensors, docking mode, rotation lock, and other factors. * - * @param orientation An orientation constant, such as - * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param orientation An orientation constant, such as + * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. * @param lastRotation The most recently used rotation. * @return The surface rotation to use. */ @VisibleForTesting - int rotationForOrientation(int orientation, int lastRotation) { - ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s", - orientation, lastRotation, mUserRotation, - mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED - ? "USER_ROTATION_LOCKED" : "" - ); + @Surface.Rotation + int rotationForOrientation(@ScreenOrientation int orientation, + @Surface.Rotation int lastRotation) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", + ActivityInfo.screenOrientationToString(orientation), orientation, + Surface.rotationToString(lastRotation), lastRotation, + Surface.rotationToString(mUserRotation), mUserRotation, + mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED + ? "USER_ROTATION_LOCKED" : ""); if (isFixedToUserRotation()) { return mUserRotation; diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 33b0453a25ee..02413bb48518 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -23,8 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Context.DEVICE_POLICY_SERVICE; import static android.content.Context.STATUS_BAR_SERVICE; import static android.content.Intent.ACTION_CALL_EMERGENCY; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; @@ -341,20 +339,6 @@ public class LockTaskController { & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0; } - boolean isActivityAllowed(int userId, String packageName, int lockTaskLaunchMode) { - if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED) { - return true; - } - switch (lockTaskLaunchMode) { - case LOCK_TASK_LAUNCH_MODE_ALWAYS: - return true; - case LOCK_TASK_LAUNCH_MODE_NEVER: - return false; - default: - } - return isPackageWhitelisted(userId, packageName); - } - private boolean isEmergencyCallTask(Task task) { final Intent intent = task.intent; if (intent == null) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0b54245cd424..e6fd512df72c 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -164,7 +164,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; @@ -2348,18 +2347,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } } - - if (displayShouldSleep || mStackSupervisor.mGoingToSleepActivities.isEmpty()) { - continue; - } - // The display is awake now, so clean up the going to sleep list. - for (Iterator<ActivityRecord> it = - mStackSupervisor.mGoingToSleepActivities.iterator(); it.hasNext(); ) { - final ActivityRecord r = it.next(); - if (r.getDisplayId() == display.mDisplayId) { - it.remove(); - } - } } } @@ -3578,9 +3565,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ", "Stop", false, !dumpAll, false, dumpPackage, true, " Activities waiting to stop:", null); - printed |= dumpHistoryList(fd, pw, mStackSupervisor.mGoingToSleepActivities, - " ", "Sleep", false, !dumpAll, - false, dumpPackage, true, " Activities waiting to sleep:", null); return printed; } diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index bfb69172e9eb..e7aca898b19d 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -370,6 +370,11 @@ class ScreenRotationAnimation { } } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Start rotation animation. customAnim=%s, " + + "mCurRotation=%s, mOriginalRotation=%s", + customAnim, Surface.rotationToString(mCurRotation), + Surface.rotationToString(mOriginalRotation)); + mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); mRotateExitAnimation.restrictDuration(maxAnimationDuration); mRotateExitAnimation.scaleCurrentDuration(animationScale); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 55ba3b6449cd..9dba0d3ee051 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,13 +16,13 @@ package com.android.server.wm; -import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -59,6 +59,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; +import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; import static com.android.server.am.TaskRecordProto.FULLSCREEN; @@ -99,6 +101,7 @@ import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.dipToPixel; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static java.lang.Integer.MAX_VALUE; @@ -210,6 +213,8 @@ class Task extends WindowContainer<WindowContainer> { static final int PERSIST_TASK_VERSION = 1; static final int INVALID_MIN_SIZE = -1; + private float mShadowRadius = 0; + private final Rect mLastSurfaceCrop = new Rect(); /** * The modes to control how the stack is moved to the front when calling {@link Task#reparent}. @@ -362,6 +367,7 @@ class Task extends WindowContainer<WindowContainer> { * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was * moved to a new display. */ + @Surface.Rotation private int mRotation; // For comparison with DisplayContent bounds. @@ -496,7 +502,7 @@ class Task extends WindowContainer<WindowContainer> { } class TaskToken extends RemoteToken { - TaskToken(ConfigurationContainer container) { + TaskToken(WindowContainer container) { super(container); } @@ -1869,6 +1875,7 @@ class Task extends WindowContainer<WindowContainer> { super.onConfigurationChanged(newParentConfig); if (wasInMultiWindowMode != inMultiWindowMode()) { mStackSupervisor.scheduleUpdateMultiWindowMode(this); + updateShadowsRadius(isFocused(), getPendingTransaction()); } // If the configuration supports persistent bounds (eg. Freeform), keep track of the @@ -2527,18 +2534,36 @@ class Task extends WindowContainer<WindowContainer> { ? getStack().getDisplayContent() : null; if (displayContent != null) { rotation = displayContent.getDisplayInfo().rotation; - } else if (bounds == null) { - return super.setBounds(bounds); } final int boundsChange = super.setBounds(bounds); - mRotation = rotation; - updateSurfacePosition(); return boundsChange; } + private void updateSurfaceCrop() { + // Only update the crop if we are drawing shadows on the task. + if (mSurfaceControl == null || !mWmService.mRenderShadowsInCompositor) { + return; + } + + if (inSplitScreenWindowingMode()) { + // inherit crop from parent + mTmpRect.setEmpty(); + } else { + getBounds(mTmpRect); + } + + mTmpRect.offsetTo(0, 0); + if (mLastSurfaceCrop.equals(mTmpRect)) { + return; + } + + getPendingTransaction().setWindowCrop(mSurfaceControl, mTmpRect); + mLastSurfaceCrop.set(mTmpRect); + } + @Override public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer) { @@ -3127,6 +3152,9 @@ class Task extends WindowContainer<WindowContainer> { } else { mTmpDimBoundsRect.offsetTo(0, 0); } + + updateSurfaceCrop(); + if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { scheduleAnimation(); } @@ -3926,4 +3954,58 @@ class Task extends WindowContainer<WindowContainer> { setTaskOrganizer(org); } } + + /** + * @return true if the task is currently focused. + */ + private boolean isFocused() { + if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) { + return false; + } + return mDisplayContent.mCurrentFocus.getTask() == this; + } + + /** + * @return the desired shadow radius in pixels for the current task. + */ + private float getShadowRadius(boolean taskIsFocused) { + if (mDisplayContent == null) { + return 0; + } + + if (inPinnedWindowingMode()) { + return dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, + mDisplayContent.getDisplayMetrics()); + } + if (inFreeformWindowingMode()) { + final int elevation = taskIsFocused + ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; + return dipToPixel(elevation, mDisplayContent.getDisplayMetrics()); + } + + // For all other windowing modes, do not draw a shadow. + return 0; + } + + /** + * Update the length of the shadow if needed based on windowing mode and task focus state. + */ + private void updateShadowsRadius(boolean taskIsFocused, + SurfaceControl.Transaction pendingTransaction) { + if (!mWmService.mRenderShadowsInCompositor) return; + + final float newShadowRadius = getShadowRadius(taskIsFocused); + if (mShadowRadius != newShadowRadius) { + mShadowRadius = newShadowRadius; + pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius); + } + } + + /** + * Called on the task of a window which gained or lost focus. + * @param hasFocus + */ + void onWindowFocusChanged(boolean hasFocus) { + updateShadowsRadius(hasFocus, getPendingTransaction()); + } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 4cb5de44bef0..10d6823c850f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -343,6 +343,7 @@ class TaskSnapshotController { builder.setPixelFormat(pixelFormat); builder.setIsTranslucent(isTranslucent); builder.setOrientation(activity.getTask().getConfiguration().orientation); + builder.setRotation(activity.getTask().getDisplayContent().getRotation()); builder.setWindowingMode(task.getWindowingMode()); builder.setSystemUiVisibility(getSystemUiVisibility(task)); return true; @@ -492,7 +493,8 @@ class TaskSnapshotController { return new TaskSnapshot( System.currentTimeMillis() /* id */, topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(), - hwBitmap.getColorSpace(), topChild.getTask().getConfiguration().orientation, + hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, + mainWindow.getWindowConfiguration().getRotation(), getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* reduced */, mFullSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), false); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 22c1ea59d176..6e9986ffd411 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -102,8 +102,8 @@ class TaskSnapshotLoader { // For legacy snapshots, restore the scale based on the reduced resolution state final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f; final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale; - return new TaskSnapshot(proto.id, topActivityComponent, buffer, - hwBitmap.getColorSpace(), proto.orientation, + return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(), + proto.orientation, proto.rotation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility, proto.isTranslucent); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 828775a4b934..ee5098b6c699 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -342,6 +342,7 @@ class TaskSnapshotPersister { boolean writeProto() { final TaskSnapshotProto proto = new TaskSnapshotProto(); proto.orientation = mSnapshot.getOrientation(); + proto.rotation = mSnapshot.getRotation(); proto.insetLeft = mSnapshot.getContentInsets().left; proto.insetTop = mSnapshot.getContentInsets().top; proto.insetRight = mSnapshot.getContentInsets().right; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 1c876d9cc02f..015b92c7cd03 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -61,6 +61,7 @@ import android.util.Pools; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; +import android.view.IWindowContainer; import android.view.MagnificationSpec; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; @@ -75,6 +76,7 @@ import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; @@ -249,6 +251,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private boolean mIsFocusable = true; + /** + * Used as a unique, cross-process identifier for this Container. It also serves a minimal + * interface to other processes. + */ + RemoteToken mRemoteToken = null; + WindowContainer(WindowManagerService wms) { mWmService = wms; mPendingTransaction = wms.mTransactionFactory.get(); @@ -860,13 +868,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return false; } - @Override + /** + * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, + * this will not be focusable either. + */ boolean isFocusable() { - return super.isFocusable() && mIsFocusable; + final WindowContainer parent = getParent(); + return (parent == null || parent.isFocusable()) && mIsFocusable; } /** Set whether this container or its children can be focusable */ - @Override boolean setFocusable(boolean focusable) { if (mIsFocusable == focusable) { return false; @@ -1068,8 +1079,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) { // Use the orientation if the container fills its parent or requested an explicit // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED. - ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", toString(), - orientation, ActivityInfo.screenOrientationToString(orientation)); + ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", + wc.toString(), orientation, + ActivityInfo.screenOrientationToString(orientation)); return orientation; } } @@ -2259,4 +2271,40 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< ActivityRecord asActivityRecord() { return null; } + + RemoteToken getRemoteToken() { + return mRemoteToken; + } + + static class RemoteToken extends IWindowContainer.Stub { + final WeakReference<WindowContainer> mWeakRef; + + RemoteToken(WindowContainer container) { + mWeakRef = new WeakReference<>(container); + } + + WindowContainer getContainer() { + return mWeakRef.get(); + } + + static RemoteToken fromBinder(IBinder binder) { + return (RemoteToken) binder; + } + + @Override + public SurfaceControl getLeash() { + throw new RuntimeException("Not implemented"); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("RemoteToken{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(mWeakRef.get()); + sb.append('}'); + return sb.toString(); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8d4ad28972e9..e13083007237 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -39,6 +39,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES; +import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.DOCKED_INVALID; @@ -122,6 +123,7 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManagerInternal; @@ -420,6 +422,11 @@ public class WindowManagerService extends IWindowManager.Stub int mVr2dDisplayId = INVALID_DISPLAY; boolean mVrModeEnabled = false; + /* If true, shadows drawn around the window will be rendered by the system compositor. If + * false, shadows will be drawn by the client by setting an elevation on the root view and + * the contents will be inset by the shadow radius. */ + boolean mRenderShadowsInCompositor = false; + /** * Tracks a map of input tokens to info that is used to decide whether to intercept * a key event. @@ -721,6 +728,8 @@ public class WindowManagerService extends IWindowManager.Stub DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES); private final Uri mSizeCompatFreeformUri = Settings.Global.getUriFor( DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM); + private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor( + DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR); public SettingsObserver() { super(new Handler()); @@ -743,6 +752,8 @@ public class WindowManagerService extends IWindowManager.Stub resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL); resolver.registerContentObserver(mSizeCompatFreeformUri, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this, + UserHandle.USER_ALL); } @Override @@ -781,6 +792,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mRenderShadowsInCompositorUri.equals(uri)) { + setShadowRenderer(); + return; + } + @UpdateAnimationScaleMode final int mode; if (mWindowAnimationScaleUri.equals(uri)) { @@ -862,6 +878,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + private void setShadowRenderer() { + mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(), + DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0; + } + PowerManager mPowerManager; PowerManagerInternal mPowerManagerInternal; @@ -1248,6 +1269,7 @@ public class WindowManagerService extends IWindowManager.Stub float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha}; SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ, lightRadius); + setShadowRenderer(); } /** @@ -2996,7 +3018,13 @@ public class WindowManagerService extends IWindowManager.Stub } } - void showGlobalActions() { + @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + @Override + public void showGlobalActions() { + if (!checkCallingPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, + "showGlobalActions()")) { + throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); + } mPolicy.showGlobalActions(); } @@ -7004,15 +7032,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver); } - @Override - public void requestUserActivityNotification() { - if (!checkCallingPermission(android.Manifest.permission.USER_ACTIVITY, - "requestUserActivityNotification()")) { - throw new SecurityException("Requires USER_ACTIVITY permission"); - } - mPolicy.requestUserActivityNotification(); - } - private final class LocalService extends WindowManagerInternal { @Override diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 08a759227526..12de20cc3d51 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -28,6 +28,7 @@ #include <android/hardware/gnss/2.0/IGnssMeasurement.h> #include <android/hardware/gnss/2.1/IGnssMeasurement.h> #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h> +#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h> #include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h> #include <nativehelper/JNIHelp.h> #include "jni.h" @@ -88,6 +89,9 @@ static jmethodID method_correctionsGetHorPosUncMeters; static jmethodID method_correctionsGetVerPosUncMeters; static jmethodID method_correctionsGetToaGpsNanosecondsOfWeek; static jmethodID method_correctionsGetSingleSatCorrectionList; +static jmethodID method_correctionsHasEnvironmentBearing; +static jmethodID method_correctionsGetEnvironmentBearingDegrees; +static jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees; static jmethodID method_listSize; static jmethodID method_correctionListGet; static jmethodID method_correctionSatFlags; @@ -142,7 +146,9 @@ using android::hardware::gnss::V1_0::IGnssXtraCallback; using android::hardware::gnss::V2_0::ElapsedRealtimeFlags; -using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; +using MeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; +using MeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections; + using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection; using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane; @@ -184,7 +190,8 @@ using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching; using IGnssBatchingCallback_V1_0 = android::hardware::gnss::V1_0::IGnssBatchingCallback; using IGnssBatchingCallback_V2_0 = android::hardware::gnss::V2_0::IGnssBatchingCallback; -using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; +using IMeasurementCorrections_V1_0 = android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; +using IMeasurementCorrections_V1_1 = android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections; using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback; using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags; @@ -231,7 +238,8 @@ sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr; sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr; sp<IGnssMeasurement_V2_1> gnssMeasurementIface_V2_1 = nullptr; sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr; -sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr; +sp<IMeasurementCorrections_V1_0> gnssCorrectionsIface_V1_0 = nullptr; +sp<IMeasurementCorrections_V1_1> gnssCorrectionsIface_V1_1 = nullptr; sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr; #define WAKE_LOCK_NAME "GPS" @@ -1735,6 +1743,13 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, method_correctionsGetSingleSatCorrectionList = env->GetMethodID( measCorrClass, "getSingleSatelliteCorrectionList", "()Ljava/util/List;"); + method_correctionsHasEnvironmentBearing = env->GetMethodID( + measCorrClass, "hasEnvironmentBearing", "()Z"); + method_correctionsGetEnvironmentBearingDegrees = env->GetMethodID( + measCorrClass, "getEnvironmentBearingDegrees", "()F"); + method_correctionsGetEnvironmentBearingUncertaintyDegrees = env->GetMethodID( + measCorrClass, "getEnvironmentBearingUncertaintyDegrees", "()F"); + jclass corrListClass = env->FindClass("java/util/List"); method_listSize = env->GetMethodID(corrListClass, "size", "()I"); method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;"); @@ -1917,12 +1932,20 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass } } - if (gnssHal_V2_0 != nullptr) { + if (gnssHal_V2_1 != nullptr) { + auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1(); + if (!gnssCorrections.isOk()) { + ALOGD("Unable to get a handle to GnssMeasurementCorrections 1.1 interface"); + } else { + gnssCorrectionsIface_V1_1 = gnssCorrections; + gnssCorrectionsIface_V1_0 = gnssCorrectionsIface_V1_1; + } + } else if (gnssHal_V2_0 != nullptr) { auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections(); if (!gnssCorrections.isOk()) { ALOGD("Unable to get a handle to GnssMeasurementCorrections interface"); } else { - gnssCorrectionsIface = gnssCorrections; + gnssCorrectionsIface_V1_0 = gnssCorrections; } } @@ -2153,11 +2176,18 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject } // Set IMeasurementCorrections.hal callback. - if (gnssCorrectionsIface != nullptr) { + if (gnssCorrectionsIface_V1_1 != nullptr) { + sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface = + new MeasurementCorrectionsCallback(); + result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface); + checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed."); + } else if (gnssCorrectionsIface_V1_0 != nullptr) { sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface = new MeasurementCorrectionsCallback(); - result = gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface); - checkHidlReturn(result, "IMeasurementCorrections setCallback() failed."); + result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface); + checkHidlReturn(result, "IMeasurementCorrections 1.0 setCallback() failed."); + } else { + ALOGI("Unable to find IMeasurementCorrections."); } return JNI_TRUE; @@ -2760,7 +2790,7 @@ static jboolean android_location_GnssMeasurementsProvider_stop_measurement_colle static jboolean android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported( JNIEnv* env, jclass clazz) { - if (gnssCorrectionsIface != nullptr) { + if (gnssCorrectionsIface_V1_0 != nullptr || gnssCorrectionsIface_V1_1 != nullptr) { return JNI_TRUE; } @@ -2773,24 +2803,12 @@ static jboolean jobject obj /* clazz*/, jobject correctionsObj) { - if (gnssCorrectionsIface == nullptr) { + if (gnssCorrectionsIface_V1_0 == nullptr && gnssCorrectionsIface_V1_1 == nullptr) { ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not" " support them."); return JNI_FALSE; } - jdouble latitudeDegreesCorr = env->CallDoubleMethod( - correctionsObj, method_correctionsGetLatitudeDegrees); - jdouble longitudeDegreesCorr = env->CallDoubleMethod( - correctionsObj, method_correctionsGetLongitudeDegrees); - jdouble altitudeDegreesCorr = env->CallDoubleMethod( - correctionsObj, method_correctionsGetAltitudeMeters); - jdouble horizontalPositionUncertaintyMeters = env->CallDoubleMethod( - correctionsObj, method_correctionsGetHorPosUncMeters); - jdouble verticalPositionUncertaintyMeters = env->CallDoubleMethod( - correctionsObj, method_correctionsGetVerPosUncMeters); - jlong toaGpsNanosOfWeek = env->CallLongMethod( - correctionsObj, method_correctionsGetToaGpsNanosecondsOfWeek); jobject singleSatCorrectionList = env->CallObjectMethod(correctionsObj, method_correctionsGetSingleSatCorrectionList); @@ -2859,7 +2877,21 @@ static jboolean }; list[i] = singleSatCorrection; } - MeasurementCorrections measurementCorrections = { + + jdouble latitudeDegreesCorr = env->CallDoubleMethod( + correctionsObj, method_correctionsGetLatitudeDegrees); + jdouble longitudeDegreesCorr = env->CallDoubleMethod( + correctionsObj, method_correctionsGetLongitudeDegrees); + jdouble altitudeDegreesCorr = env->CallDoubleMethod( + correctionsObj, method_correctionsGetAltitudeMeters); + jdouble horizontalPositionUncertaintyMeters = env->CallDoubleMethod( + correctionsObj, method_correctionsGetHorPosUncMeters); + jdouble verticalPositionUncertaintyMeters = env->CallDoubleMethod( + correctionsObj, method_correctionsGetVerPosUncMeters); + jlong toaGpsNanosOfWeek = env->CallLongMethod( + correctionsObj, method_correctionsGetToaGpsNanosecondsOfWeek); + + MeasurementCorrections_V1_0 measurementCorrections_1_0 = { .latitudeDegrees = latitudeDegreesCorr, .longitudeDegrees = longitudeDegreesCorr, .altitudeMeters = altitudeDegreesCorr, @@ -2869,8 +2901,28 @@ static jboolean .satCorrections = list, }; - auto result = gnssCorrectionsIface->setCorrections(measurementCorrections); - return checkHidlReturn(result, "IMeasurementCorrections setCorrections() failed."); + if (gnssCorrectionsIface_V1_1 != nullptr) { + + jboolean hasEnvironmentBearingCorr = env->CallBooleanMethod( + correctionsObj, method_correctionsHasEnvironmentBearing); + jfloat environmentBearingDegreesCorr = env->CallFloatMethod( + correctionsObj, method_correctionsGetEnvironmentBearingDegrees); + jfloat environmentBearingUncertaintyDegreesCorr = env->CallFloatMethod( + correctionsObj, method_correctionsGetEnvironmentBearingUncertaintyDegrees); + + MeasurementCorrections_V1_1 measurementCorrections_1_1 = { + .v1_0 = measurementCorrections_1_0, + .hasEnvironmentBearing = static_cast<bool>(hasEnvironmentBearingCorr), + .environmentBearingDegrees = environmentBearingDegreesCorr, + .environmentBearingUncertaintyDegrees = environmentBearingUncertaintyDegreesCorr, + }; + + auto result = gnssCorrectionsIface_V1_1->setCorrections_1_1(measurementCorrections_1_1); + return checkHidlReturn(result, "IMeasurementCorrections 1.1 setCorrections() failed."); + } + + auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0); + return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed."); } static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported( diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 82f5d50b41c7..d7ea2f53c286 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -180,6 +180,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Color; import android.location.LocationManager; +import android.location.LocationManagerInternal; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; @@ -2096,6 +2097,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return mContext.getSystemService(LocationManager.class); } + LocationManagerInternal getLocationManagerInternal() { + return LocalServices.getService(LocationManagerInternal.class); + } + IWindowManager getIWindowManager() { return IWindowManager.Stub .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); @@ -11553,6 +11558,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public void requestSetLocationProviderAllowed(ComponentName who, String provider, + boolean providerAllowed) { + Objects.requireNonNull(who, "ComponentName is null"); + enforceDeviceOwner(who); + + mInjector.binderWithCleanCallingIdentity( + () -> mInjector.getLocationManagerInternal().requestSetProviderAllowed(provider, + providerAllowed)); + } + + @Override public boolean setTime(ComponentName who, long millis) { Objects.requireNonNull(who, "ComponentName is null in setTime"); enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java index f037692886ab..1985513c4290 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java @@ -120,7 +120,7 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_3); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleFullFull).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4); - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo( + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); @@ -209,7 +209,7 @@ public final class CachedAppOptimizerTest { CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1); - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo( + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleBFGS).isEqualTo( CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1); @@ -472,7 +472,7 @@ public final class CachedAppOptimizerTest { public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException { mCachedAppOptimizerUnderTest.init(); - // When we override mStatsdSampleRate with a reasonable value ... + // When we override mCompactStatsdSampleRate with a reasonable value ... mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, @@ -480,7 +480,7 @@ public final class CachedAppOptimizerTest { assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); // Then that override is reflected in the compactor. - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo( + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); } @@ -489,14 +489,14 @@ public final class CachedAppOptimizerTest { throws InterruptedException { mCachedAppOptimizerUnderTest.init(); - // When we override mStatsdSampleRate with an unreasonable value ... + // When we override mCompactStatsdSampleRate with an unreasonable value ... mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false); assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); // Then that override is reflected in the compactor. - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo( + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo( CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE); } @@ -505,7 +505,7 @@ public final class CachedAppOptimizerTest { throws InterruptedException { mCachedAppOptimizerUnderTest.init(); - // When we override mStatsdSampleRate with an value outside of [0..1]... + // When we override mCompactStatsdSampleRate with an value outside of [0..1]... mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE, @@ -513,7 +513,7 @@ public final class CachedAppOptimizerTest { assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); // Then the values is capped in the range. - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo(0.0f); + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(0.0f); mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -522,7 +522,7 @@ public final class CachedAppOptimizerTest { assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); // Then the values is capped in the range. - assertThat(mCachedAppOptimizerUnderTest.mStatsdSampleRate).isEqualTo(1.0f); + assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(1.0f); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 067f23a5bb23..155de3bc0266 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -283,6 +283,8 @@ public class AppOpsServiceTest { } + /* + TODO ntmyren: re enable when we have time to rewrite test. @Test public void testPackageRemovedHistoricalOps() throws InterruptedException { mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); @@ -321,6 +323,7 @@ public class AppOpsServiceTest { assertThat(latchRef.get().getCount()).isEqualTo(0); assertThat(resultOpsRef.get().isEmpty()).isTrue(); } + */ @Test public void testUidRemoved() { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 1c88c40c3e2b..e724e60b3ae5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -27,6 +28,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX; +import static com.android.server.job.JobSchedulerService.RARE_INDEX; +import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -568,6 +572,48 @@ public class ConnectivityControllerTest { assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED)); } + @Test + public void testRestrictedJobTracking() { + final JobStatus networked = createJobStatus(createJob() + .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR), UID_RED); + final JobStatus unnetworked = createJobStatus(createJob(), UID_BLUE); + networked.setStandbyBucket(FREQUENT_INDEX); + unnetworked.setStandbyBucket(FREQUENT_INDEX); + + final Network cellularNet = new Network(101); + final NetworkCapabilities cellularCaps = + createCapabilities().addTransportType(TRANSPORT_CELLULAR); + reset(mConnManager); + answerNetwork(UID_RED, cellularNet, cellularCaps); + answerNetwork(UID_BLUE, cellularNet, cellularCaps); + + final ConnectivityController controller = new ConnectivityController(mService); + controller.maybeStartTrackingJobLocked(networked, null); + controller.maybeStartTrackingJobLocked(unnetworked, null); + + assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + + networked.setStandbyBucket(RESTRICTED_INDEX); + unnetworked.setStandbyBucket(RESTRICTED_INDEX); + controller.startTrackingRestrictedJobLocked(networked); + controller.startTrackingRestrictedJobLocked(unnetworked); + assertFalse(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a + // connectivity constraint. + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + + networked.setStandbyBucket(RARE_INDEX); + unnetworked.setStandbyBucket(RARE_INDEX); + controller.stopTrackingRestrictedJobLocked(networked); + controller.stopTrackingRestrictedJobLocked(unnetworked); + assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a + // connectivity constraint. + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + } + private void answerNetwork(int uid, Network net, NetworkCapabilities caps) { when(mConnManager.getActiveNetworkForUid(eq(uid))).thenReturn(net); when(mConnManager.getNetworkCapabilities(eq(net))).thenReturn(caps); diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java index 4d229efc8328..625766a97f13 100644 --- a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java +++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java @@ -157,6 +157,8 @@ public class WatchdogDiagnosticsTest { String expected = "TestThread2 annotated stack trace:\n" + " at java.lang.Object.wait(Native Method)\n" + + " at java.lang.Object.wait(Object.java:442)\n" + + " at java.lang.Object.wait(Object.java:568)\n" + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" + "WatchdogDiagnosticsTest.java:91)\n" + " - locked <HASH> (a java.lang.String)\n" + diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index a6af9a99788f..770afb0a24d5 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -32,11 +32,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.mockito.internal.verification.VerificationModeFactory.times; import android.content.BroadcastReceiver; import android.content.Context; @@ -57,10 +55,8 @@ import android.os.Handler; import android.os.Message; import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; -import com.android.server.LocalServices; import com.android.server.integrity.engine.RuleEvaluationEngine; import com.android.server.integrity.model.IntegrityCheckResult; import com.android.server.testutils.TestUtils; @@ -68,6 +64,7 @@ import com.android.server.testutils.TestUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -81,7 +78,7 @@ import java.util.List; import java.util.Map; /** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */ -@RunWith(AndroidJUnit4.class) +@RunWith(JUnit4.class) public class AppIntegrityManagerServiceImplTest { private static final String TEST_APP_PATH = "/data/local/tmp/AppIntegrityManagerServiceTestApp.apk"; @@ -91,8 +88,10 @@ public class AppIntegrityManagerServiceImplTest { private static final String TEST_FRAMEWORK_PACKAGE = "com.android.frameworks.servicestests"; private static final String PACKAGE_NAME = "com.test.app"; - private static final int VERSION_CODE = 100; + + private static final long VERSION_CODE = 100; private static final String INSTALLER = "com.long.random.test.installer.name"; + // These are obtained by running the test and checking logcat. private static final String APP_CERT = "301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA"; @@ -108,7 +107,8 @@ public class AppIntegrityManagerServiceImplTest { "play_store_cert"; private static final String ADB_CERT = ""; - @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); + @org.junit.Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); @Mock PackageManagerInternal mPackageManagerInternal; @Mock Context mMockContext; @@ -144,36 +144,16 @@ public class AppIntegrityManagerServiceImplTest { when(mIntegrityFileManager.initialized()).thenReturn(true); } - // This is not a test of the class, but more of a safeguard that we don't block any install in - // the default case. This is needed because we don't have any emergency kill switch to disable - // this component. - @Test - public void default_allow() throws Exception { - LocalServices.removeServiceForTest(PackageManagerInternal.class); - LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); - mService = AppIntegrityManagerServiceImpl.create(mMockContext); - ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = - ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mMockContext, times(2)) - .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any()); - Intent intent = makeVerificationIntent(); - - broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); - - // Since we are not mocking handler in this case, we must wait. - // 2 seconds should be a sensible timeout. - Thread.sleep(2000); - verify(mPackageManagerInternal) - .setIntegrityVerificationResult( - 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - } + // TODO(b/148370598): Implement a test to validate that allow response is retuned when the test + // request times out. @Test public void updateRuleSet_notAuthorized() throws Exception { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -191,7 +171,8 @@ public class AppIntegrityManagerServiceImplTest { whitelistUsAsRuleProvider(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); TestUtils.assertExpectException( SecurityException.class, @@ -210,7 +191,8 @@ public class AppIntegrityManagerServiceImplTest { makeUsSystemApp(); Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); // no SecurityException @@ -375,10 +357,10 @@ public class AppIntegrityManagerServiceImplTest { broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); runJobInHandler(); + // The evaluation will still run since we still evaluate manifest based rules. verify(mPackageManagerInternal) .setIntegrityVerificationResult( 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - verify(mSpyPackageManager, never()).getPackageArchiveInfo(any(), anyInt()); } @Test @@ -426,8 +408,8 @@ public class AppIntegrityManagerServiceImplTest { private Intent makeVerificationIntent() throws Exception { PackageInfo packageInfo = - mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, - PackageManager.GET_SIGNATURES); + mRealContext.getPackageManager() + .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES); doReturn(packageInfo) .when(mSpyPackageManager) .getPackageInfo(eq(INSTALLER), anyInt()); @@ -447,7 +429,7 @@ public class AppIntegrityManagerServiceImplTest { intent.putExtra( EXTRA_VERIFICATION_INSTALLER_UID, mMockContext.getPackageManager().getPackageUid(installer, /* flags= */ 0)); - intent.putExtra(Intent.EXTRA_VERSION_CODE, VERSION_CODE); + intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE); return intent; } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java index a1810b971b09..86daf69fb2d9 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java @@ -22,7 +22,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; -import android.content.integrity.AtomicFormula.IntAtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Rule; @@ -116,7 +116,8 @@ public class IntegrityFileManagerTest { Rule packageCertRule = getAppCertificateIndexedRule(packageCert); Rule versionCodeRule = new Rule( - new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, version), + new LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, version), Rule.DENY); Rule randomRule = new Rule( @@ -127,9 +128,9 @@ public class IntegrityFileManagerTest { AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false), - new IntAtomicFormula( + new LongAtomicFormula( AtomicFormula.VERSION_CODE, - AtomicFormula.LE, + AtomicFormula.EQ, version))), Rule.DENY); @@ -201,21 +202,22 @@ public class IntegrityFileManagerTest { private Rule getPackageNameIndexedRule(String packageName) { return new Rule( new StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */ false), + AtomicFormula.PACKAGE_NAME, packageName, /* isHashedValue= */false), Rule.DENY); } private Rule getAppCertificateIndexedRule(String appCertificate) { return new Rule( new StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, appCertificate, /* isHashedValue= */ false), + AtomicFormula.APP_CERTIFICATE, + appCertificate, /* isHashedValue= */ false), Rule.DENY); } private Rule getInstallerCertificateRule(String installerCert) { return new Rule( new StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, installerCert, /* isHashedValue= */ false), + AtomicFormula.INSTALLER_NAME, installerCert, /* isHashedValue= */false), Rule.DENY); } diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java index d3864878d4b2..26b20965fbf5 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java @@ -16,12 +16,12 @@ package com.android.server.integrity.engine; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.integrity.AppInstallMetadata; -import android.content.integrity.Rule; import com.android.server.integrity.IntegrityFileManager; import com.android.server.integrity.model.IntegrityCheckResult; @@ -36,7 +36,6 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; @RunWith(JUnit4.class) @@ -50,7 +49,8 @@ public class RuleEvaluationEngineTest { private static final String RANDOM_INSTALLER = "random"; private static final String RANDOM_INSTALLER_CERT = "random_cert"; - @Mock private IntegrityFileManager mIntegrityFileManager; + @Mock + private IntegrityFileManager mIntegrityFileManager; private RuleEvaluationEngine mEngine; @@ -67,33 +67,28 @@ public class RuleEvaluationEngineTest { public void testAllowedInstallers_empty() { Map<String, String> allowedInstallers = Collections.emptyMap(); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); } @Test @@ -101,87 +96,100 @@ public class RuleEvaluationEngineTest { Map<String, String> allowedInstallers = Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata4 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); } @Test public void testAllowedInstallers_multipleElement() { - List<Rule> rules = new ArrayList<>(); Map<String, String> allowedInstallers = new HashMap<>(2); allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT); allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata4 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + } + + @Test + public void manifestBasedRuleEvaluationWorksEvenWhenIntegrityFilesAreUnavailable() { + when(mIntegrityFileManager.initialized()).thenReturn(false); + + Map<String, String> allowedInstallers = + Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT); + + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java index eda2b701fd8d..629fd14befcc 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java @@ -19,10 +19,11 @@ package com.android.server.integrity.engine; import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW; import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; +import android.content.integrity.AtomicFormula.LongAtomicFormula; import android.content.integrity.AtomicFormula.StringAtomicFormula; import android.content.integrity.CompoundFormula; import android.content.integrity.Rule; @@ -57,7 +58,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(ALLOW); } @Test @@ -73,7 +74,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule1), APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(ALLOW); } @Test @@ -96,8 +97,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule1); } @Test @@ -126,8 +127,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule1); } @Test @@ -145,23 +146,23 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test public void testEvaluateRules_ruleWithIntegerOperators_deny() { Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1), + new LongAtomicFormula(AtomicFormula.VERSION_CODE, + AtomicFormula.GT, 1), Rule.DENY); IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test @@ -183,8 +184,8 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); - assertEquals(rule, result.getRule()); + assertThat(result.getEffect()).isEqualTo(DENY); + assertThat(result.getRule()).isEqualTo(rule); } @Test @@ -206,7 +207,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(DENY); } @Test @@ -230,7 +231,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA); - assertEquals(DENY, result.getEffect()); + assertThat(result.getEffect()).isEqualTo(DENY); } @Test @@ -259,7 +260,7 @@ public class RuleEvaluatorTest { IntegrityCheckResult result = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA); - assertEquals(ALLOW, result.getEffect()); - assertEquals(rule1, result.getRule()); + assertThat(result.getEffect()).isEqualTo(ALLOW); + assertThat(result.getRule()).isEqualTo(rule1); } -} +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java index cfa1de371e8c..723b6c5af451 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/BinaryFileOperationsTest.java @@ -26,7 +26,8 @@ import static com.android.server.integrity.utils.TestUtils.getValueBits; import static com.google.common.truth.Truth.assertThat; -import com.android.server.integrity.IntegrityUtils; +import android.content.integrity.IntegrityUtils; + import com.android.server.integrity.model.BitInputStream; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java index e0b2e2257ee4..38cf562f8c5b 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java @@ -36,10 +36,9 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; -import com.android.server.integrity.IntegrityUtils; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -345,7 +344,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY + END_BIT; byte[] ruleBytes = getBytes(ruleBits); @@ -356,7 +355,7 @@ public class RuleBinaryParserTest { RuleParser binaryParser = new RuleBinaryParser(); Rule expectedRule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); @@ -384,7 +383,8 @@ public class RuleBinaryParserTest { RuleParser binaryParser = new RuleBinaryParser(); Rule expectedRule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); List<Rule> rules = binaryParser.parse(rule.array()); @@ -400,7 +400,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY; byte[] ruleBytes = getBytes(ruleBits); ByteBuffer rule = @@ -488,7 +488,7 @@ public class RuleBinaryParserTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + INVALID_OPERATOR - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + COMPOUND_FORMULA_END_BITS + DENY + END_BIT; diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java index 0f0dee924e29..c57136c1acab 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java @@ -46,15 +46,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -83,15 +83,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -123,17 +123,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -168,17 +168,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + /* tag= */ "AF", appCertificateAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -211,15 +211,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -252,17 +252,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + generateTagWithAttribute( - /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -283,15 +283,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -311,15 +311,15 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", "INVALID_EFFECT"), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", "INVALID_EFFECT"), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -339,17 +339,17 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "InvalidAtomicFormula", - packageNameAttrs, - /* closed= */ true) + /* tag= */ "InvalidAtomicFormula", + packageNameAttrs, + /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -369,11 +369,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -399,17 +399,17 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + /* tag= */ "AF", versionCodeAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); Rule expectedRule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); @@ -426,17 +426,18 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + /* tag= */ "AF", preInstalledAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); Rule expectedRule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8)); @@ -452,11 +453,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -481,11 +482,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -504,11 +505,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -526,16 +527,16 @@ public class RuleXmlParserTest { String ruleXmlCompoundFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap( - "BadConnector", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap( + "BadConnector", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</OF>" + "</R>" + "</RL>"; @@ -555,11 +556,11 @@ public class RuleXmlParserTest { String ruleXmlAtomicFormula = "<RL>" + generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + /* tag= */ "AF", packageNameAttrs, /* closed= */ true) + "</R>" + "</RL>"; RuleParser xmlParser = new RuleXmlParser(); @@ -577,15 +578,15 @@ public class RuleXmlParserTest { atomicFormulaAttrs.put("V", "com.app.test"); String ruleXmlWithNoRuleList = generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>"; RuleParser xmlParser = new RuleXmlParser(); @@ -603,15 +604,15 @@ public class RuleXmlParserTest { atomicFormulaAttrs.put("V", "com.app.test"); String ruleXmlWithNoRuleList = generateTagWithAttribute( - /* tag= */ "R", - Collections.singletonMap("E", String.valueOf(Rule.DENY)), - /* closed= */ false) + /* tag= */ "R", + Collections.singletonMap("E", String.valueOf(Rule.DENY)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "OF", - Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), - /* closed= */ false) + /* tag= */ "OF", + Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)), + /* closed= */ false) + generateTagWithAttribute( - /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true) + "</OF>" + "</R>"; RuleParser xmlParser = new RuleXmlParser(); diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java index e5cbeee2860d..f3da286585fd 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java @@ -42,13 +42,12 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; +import android.content.integrity.IntegrityUtils; import android.content.integrity.Rule; import androidx.annotation.NonNull; -import com.android.server.integrity.IntegrityUtils; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -424,11 +423,12 @@ public class RuleBinarySerializerTest { @Test public void testBinaryString_serializeValidAtomicFormula_integerValue() throws Exception { - int versionCode = 1; + long versionCode = 1; Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode), + new AtomicFormula.LongAtomicFormula( + AtomicFormula.VERSION_CODE, AtomicFormula.EQ, + versionCode), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = @@ -436,7 +436,7 @@ public class RuleBinarySerializerTest { + ATOMIC_FORMULA_START_BITS + VERSION_CODE + EQ - + getBits(versionCode, /* numOfBits= */ 32) + + getBits(versionCode, /* numOfBits= */ 64) + DENY + END_BIT; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); @@ -456,7 +456,8 @@ public class RuleBinarySerializerTest { String preInstalled = "1"; Rule rule = new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, true), Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); String expectedBits = @@ -481,7 +482,7 @@ public class RuleBinarySerializerTest { @Test public void testBinaryString_serializeInvalidFormulaType() throws Exception { - Formula invalidFormula = getInvalidFormula(); + IntegrityFormula invalidFormula = getInvalidFormula(); Rule rule = new Rule(invalidFormula, Rule.DENY); RuleSerializer binarySerializer = new RuleBinarySerializer(); @@ -858,16 +859,16 @@ public class RuleBinarySerializerTest { + END_BIT; } - private static Formula getInvalidFormula() { - return new Formula() { + private static IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 0; } @Override - public int getTag() { - return 0; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java index 1674422f3af9..038ab7ff0c35 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java @@ -27,7 +27,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import androidx.annotation.NonNull; @@ -71,9 +71,11 @@ public class RuleIndexingDetailsIdentifierTest { SAMPLE_INSTALLER_CERTIFICATE, /* isHashedValue= */ false); private static final AtomicFormula ATOMIC_FORMULA_WITH_VERSION_CODE = - new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 12); + new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, + AtomicFormula.EQ, 12); private static final AtomicFormula ATOMIC_FORMULA_WITH_ISPREINSTALLED = - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, /* booleanValue= */ + new AtomicFormula.BooleanAtomicFormula( + AtomicFormula.PRE_INSTALLED, /* booleanValue= */ true); @@ -284,16 +286,16 @@ public class RuleIndexingDetailsIdentifierTest { Rule.DENY); } - private Formula getInvalidFormula() { - return new Formula() { + private IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 4; } @Override - public int getTag() { - return 4; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java index ff7722c07d29..6558cd538638 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java @@ -23,7 +23,7 @@ import static org.junit.Assert.assertEquals; import android.content.integrity.AppInstallMetadata; import android.content.integrity.AtomicFormula; import android.content.integrity.CompoundFormula; -import android.content.integrity.Formula; +import android.content.integrity.IntegrityFormula; import android.content.integrity.Rule; import androidx.annotation.NonNull; @@ -328,7 +328,7 @@ public class RuleXmlSerializerTest { public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception { Rule rule = new Rule( - new AtomicFormula.IntAtomicFormula( + new AtomicFormula.LongAtomicFormula( AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1), Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); @@ -384,7 +384,7 @@ public class RuleXmlSerializerTest { @Test public void testXmlString_serializeInvalidFormulaType() throws Exception { - Formula invalidFormula = getInvalidFormula(); + IntegrityFormula invalidFormula = getInvalidFormula(); Rule rule = new Rule(invalidFormula, Rule.DENY); RuleSerializer xmlSerializer = new RuleXmlSerializer(); @@ -530,16 +530,16 @@ public class RuleXmlSerializerTest { + "</R>"; } - private Formula getInvalidFormula() { - return new Formula() { + private IntegrityFormula getInvalidFormula() { + return new AtomicFormula(0) { @Override - public boolean isSatisfied(AppInstallMetadata appInstallMetadata) { - return false; + public int getTag() { + return 0; } @Override - public int getTag() { - return 0; + public boolean matches(AppInstallMetadata appInstallMetadata) { + return false; } @Override diff --git a/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java index e54410b04b79..55abc7c1050d 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java +++ b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java @@ -18,8 +18,8 @@ package com.android.server.integrity.utils; public class TestUtils { - public static String getBits(int component, int numOfBits) { - return String.format("%" + numOfBits + "s", Integer.toBinaryString(component)) + public static String getBits(long component, int numOfBits) { + return String.format("%" + numOfBits + "s", Long.toBinaryString(component)) .replace(' ', '0'); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 8329227360e7..cf51fa31fad3 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; import static android.content.res.Resources.ID_NULL; import static org.hamcrest.CoreMatchers.is; @@ -217,6 +219,7 @@ public class PackageManagerSettingsTests { assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL)); assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID)); assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL)); + assertThat(params.dialogInfo.getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS)); assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL)); } @@ -243,12 +246,14 @@ public class PackageManagerSettingsTests { .setTitle(0x11220002) .setMessage("1st message") .setNeutralButtonText(0x11220003) + .setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS) .build(); final SuspendDialogInfo dialogInfo2 = new SuspendDialogInfo.Builder() .setIcon(0x22220001) .setTitle(0x22220002) .setMessage("2nd message") .setNeutralButtonText(0x22220003) + .setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND) .build(); ps1.addOrUpdateSuspension("suspendingPackage1", dialogInfo1, appExtras1, launcherExtras1, diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java index a0efc8a03719..da5986f71f11 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java @@ -31,6 +31,7 @@ import org.junit.runner.RunWith; import java.io.File; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ExecutorService; /** * Tests for {@link ParallelPackageParser} @@ -43,7 +44,8 @@ public class ParallelPackageParserTest { @Before public void setUp() { - mParser = new TestParallelPackageParser(); + mParser = new TestParallelPackageParser(new PackageParser(), + ParallelPackageParser.makeExecutorService()); } @Test(timeout = 1000) @@ -68,15 +70,14 @@ public class ParallelPackageParserTest { } } - class TestParallelPackageParser extends ParallelPackageParser { + private class TestParallelPackageParser extends ParallelPackageParser { - TestParallelPackageParser() { - super(null, false, null, null, null); + TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) { + super(packageParser, executorService); } @Override - protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, - int parseFlags) throws PackageParser.PackageParserException { + protected ParsedPackage parsePackage(File scanFile, int parseFlags) { // Do not actually parse the package for testing return null; } diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java index 7eccd6728533..322e448d983f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS; +import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; @@ -39,7 +42,8 @@ public class SuspendDialogInfoTest { .setIcon(VALID_TEST_RES_ID_1) .setTitle(VALID_TEST_RES_ID_1) .setMessage(VALID_TEST_RES_ID_1) - .setNeutralButtonText(VALID_TEST_RES_ID_1); + .setNeutralButtonText(VALID_TEST_RES_ID_1) + .setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS); } @Test @@ -73,6 +77,25 @@ public class SuspendDialogInfoTest { } @Test + public void equalsComparesButtonAction() { + final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder(); + final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder(); + assertEquals(dialogBuilder1.build(), dialogBuilder2.build()); + // Only button action is different + dialogBuilder2.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND); + assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build()); + } + + @Test + public void defaultButtonAction() { + final SuspendDialogInfo.Builder dialogBuilder = new SuspendDialogInfo.Builder() + .setIcon(VALID_TEST_RES_ID_1) + .setTitle(VALID_TEST_RES_ID_1) + .setMessage(VALID_TEST_RES_ID_1); + assertEquals(BUTTON_ACTION_MORE_DETAILS, dialogBuilder.build().getNeutralButtonAction()); + } + + @Test public void equalsComparesMessageIds() { final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder(); final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder(); diff --git a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java index f1b2ef811885..5d849c114e69 100644 --- a/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/IntervalStatsTests.java @@ -92,6 +92,9 @@ public class IntervalStatsTests { case UsageEvents.Event.NOTIFICATION_INTERRUPTION: event.mNotificationChannelId = "channel" + (i % 5); //"random" channel break; + case UsageEvents.Event.LOCUS_ID_SET: + event.mLocusId = "locus" + (i % 7); //"random" locus + break; } intervalStats.addEvent(event); diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java index e6bb244ef05b..f1c39067994c 100644 --- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java +++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java @@ -52,6 +52,7 @@ import java.util.Set; public class UsageStatsDatabaseTest { private static final int MAX_TESTED_VERSION = 5; + private static final int OLDER_VERSION_MAX_EVENT_TYPE = 29; protected Context mContext; private UsageStatsDatabase mUsageStatsDatabase; private File mTestDir; @@ -79,7 +80,7 @@ public class UsageStatsDatabaseTest { mUsageStatsDatabase = new UsageStatsDatabase(mTestDir); mUsageStatsDatabase.readMappingsLocked(); mUsageStatsDatabase.init(1); - populateIntervalStats(); + populateIntervalStats(MAX_TESTED_VERSION); clearUsageStatsFiles(); } @@ -117,7 +118,7 @@ public class UsageStatsDatabaseTest { return sb.toString(); } - private void populateIntervalStats() { + private void populateIntervalStats(int minVersion) { final int numberOfEvents = 3000; final int timeProgression = 23; long time = System.currentTimeMillis() - (numberOfEvents*timeProgression); @@ -147,9 +148,12 @@ public class UsageStatsDatabaseTest { final int instanceId = i % 11; event.mClass = ".fake.class.name" + instanceId; event.mTimeStamp = time; - event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type event.mInstanceId = instanceId; + int maxEventType = (minVersion < 5) ? OLDER_VERSION_MAX_EVENT_TYPE : MAX_EVENT_TYPE; + event.mEventType = i % (maxEventType + 1); //"random" event type + + final int rootPackageInt = (i % 5); // 5 "apps" start each task event.mTaskRootPackage = "fake.package.name" + rootPackageInt; @@ -174,6 +178,9 @@ public class UsageStatsDatabaseTest { //"random" channel event.mNotificationChannelId = "channel" + (i % 5); break; + case Event.LOCUS_ID_SET: + event.mLocusId = "locus" + (i % 7); //"random" locus + break; } mIntervalStats.addEvent(event); @@ -281,6 +288,10 @@ public class UsageStatsDatabaseTest { assertEquals(e1.mNotificationChannelIdToken, e2.mNotificationChannelIdToken, "Usage event " + debugId); break; + case Event.LOCUS_ID_SET: + assertEquals(e1.mLocusIdToken, e2.mLocusIdToken, + "Usage event " + debugId); + break; } // fallthrough case 4: // test fields added in version 4 @@ -392,6 +403,7 @@ public class UsageStatsDatabaseTest { * version and read the automatically upgraded files on disk in the new file format. */ void runVersionChangeTest(int oldVersion, int newVersion, int interval) throws IOException { + populateIntervalStats(oldVersion); // Write IntervalStats to disk in old version format UsageStatsDatabase prevDB = new UsageStatsDatabase(mTestDir, oldVersion); prevDB.readMappingsLocked(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 135d00586329..399cf49ac06f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; @@ -45,7 +44,6 @@ import android.testing.DexmakerShareClassLoaderRule; import androidx.test.filters.SmallTest; -import com.android.internal.app.BlockedAppActivity; import com.android.internal.app.HarmfulAppWarningActivity; import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; @@ -107,8 +105,6 @@ public class ActivityStartInterceptorTest { private PackageManagerService mPackageManager; @Mock private ActivityManagerInternal mAmInternal; - @Mock - private LockTaskController mLockTaskController; private ActivityStartInterceptor mInterceptor; private ActivityInfo mAInfo = new ActivityInfo(); @@ -149,13 +145,6 @@ public class ActivityStartInterceptorTest { when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID)) .thenReturn(null); - // Mock LockTaskController - mAInfo.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; - when(mService.getLockTaskController()).thenReturn(mLockTaskController); - when(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)) - .thenReturn(true); - // Initialise activity info mAInfo.applicationInfo = new ApplicationInfo(); mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME; @@ -207,18 +196,6 @@ public class ActivityStartInterceptorTest { } @Test - public void testInterceptLockTaskModeViolationPackage() { - when(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)) - .thenReturn(false); - - assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null)); - - assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME) - .filterEquals(mInterceptor.mIntent)); - } - - @Test public void testInterceptQuietProfile() { // GIVEN that the user the activity is starting as is currently in quiet mode when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index 75ec53d69a71..039ff604f3f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -29,9 +29,6 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE; import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; -import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.os.Process.SYSTEM_UID; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; @@ -696,38 +693,6 @@ public class LockTaskControllerTest { assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0); } - @Test - public void testIsActivityAllowed() { - // WHEN lock task mode is not enabled - assertTrue(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); - - // WHEN lock task mode is enabled - Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED); - mLockTaskController.startLockTaskMode(tr, false, TEST_UID); - - - // package with LOCK_TASK_LAUNCH_MODE_ALWAYS should always be allowed - assertTrue(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS)); - - // unwhitelisted package should not be allowed - assertFalse(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); - - // update the whitelist - String[] whitelist = new String[] { TEST_PACKAGE_NAME }; - mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist); - - // whitelisted package should be allowed - assertTrue(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); - - // package with LOCK_TASK_LAUNCH_MODE_NEVER should never be allowed - assertFalse(mLockTaskController.isActivityAllowed( - TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_NEVER)); - } - private Task getTask(int lockTaskAuth) { return getTask(TEST_PACKAGE_NAME, lockTaskAuth); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index eb8eb98fd484..d73830468359 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -31,6 +31,7 @@ import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.view.Surface; import android.view.View; import androidx.test.filters.MediumTest; @@ -47,7 +48,7 @@ import java.util.function.Predicate; * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader} * * Build/Install/Run: - * atest WmTests:TaskSnapshotPersisterLoaderTest + * atest TaskSnapshotPersisterLoaderTest */ @MediumTest @Presubmit @@ -316,4 +317,18 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; assertTrueForFiles(existsFiles, File::exists, " must exist"); } + + @Test + public void testRotationPersistAndLoadSnapshot() { + TaskSnapshot a = new TaskSnapshotBuilder() + .setRotation(Surface.ROTATION_270) + .build(); + mPersister.persistSnapshot(1 , mTestUserId, createSnapshot()); + mPersister.persistSnapshot(2 , mTestUserId, a); + mPersister.waitForQueueEmpty(); + final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */); + final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); + assertEquals(Surface.ROTATION_0, snapshotA.getRotation()); + assertEquals(Surface.ROTATION_270, snapshotB.getRotation()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index f7496229f66b..f86c9e63dc48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -32,6 +32,7 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.UserManager; +import android.view.Surface; import org.junit.After; import org.junit.Before; @@ -93,6 +94,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { private boolean mIsTranslucent = false; private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; private int mSystemUiVisibility = 0; + private int mRotation = Surface.ROTATION_0; TaskSnapshotBuilder setScale(float scale) { mScale = scale; @@ -124,6 +126,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { return this; } + TaskSnapshotBuilder setRotation(int rotation) { + mRotation = rotation; + return this; + } + TaskSnapshot build() { final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); @@ -131,7 +138,8 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, TEST_INSETS, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + mRotation, TEST_INSETS, mReducedResolution, mScale, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index ed87f3a0c604..bb0e5aec8e2e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -40,6 +40,7 @@ import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.view.Surface; import android.view.SurfaceControl; import androidx.test.filters.SmallTest; @@ -69,7 +70,8 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final TaskSnapshot snapshot = new TaskSnapshot( System.currentTimeMillis(), new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, contentInsets, false, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + Surface.ROTATION_0, contentInsets, false, 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 9f45044c6a60..3a689246205d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -406,10 +406,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void requestUserActivityNotification() { - } - - @Override public boolean setAodShowing(boolean aodShowing) { return false; } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 5cf9c44ee9e4..186ff6b1515b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -323,11 +323,18 @@ public class WindowStateTests extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final WindowState first = createWindow(null, TYPE_APPLICATION, activity, "first"); final WindowState second = createWindow(null, TYPE_APPLICATION, activity, "second"); - second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; testPrepareWindowToDisplayDuringRelayout(first, false /* expectedWakeupCalled */, true /* expectedCurrentLaunchCanTurnScreenOn */); - testPrepareWindowToDisplayDuringRelayout(second, true /* expectedWakeupCalled */, + testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */, + true /* expectedCurrentLaunchCanTurnScreenOn */); + + // Call prepareWindowToDisplayDuringRelayout for two windows from the same activity, one of + // which has FLAG_TURN_SCREEN_ON. The first processed one should trigger the wakeup. + second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; + testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */, + false /* expectedCurrentLaunchCanTurnScreenOn */); + testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */, false /* expectedCurrentLaunchCanTurnScreenOn */); // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 8fb283adc740..8fadf5eb9333 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -28,6 +28,7 @@ import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START; import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_STOP; import static android.app.usage.UsageEvents.Event.KEYGUARD_HIDDEN; import static android.app.usage.UsageEvents.Event.KEYGUARD_SHOWN; +import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET; import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE; import static android.app.usage.UsageEvents.Event.SCREEN_INTERACTIVE; @@ -568,6 +569,16 @@ public class IntervalStats { continue; } break; + case LOCUS_ID_SET: + event.mLocusId = packagesTokenData.getString(packageToken, event.mLocusIdToken); + if (event.mLocusId == null) { + Slog.e(TAG, "Unable to parse locus " + event.mLocusIdToken + + " for package " + packageToken); + this.events.remove(i); + dataOmitted = true; + continue; + } + break; } } return dataOmitted; @@ -675,6 +686,12 @@ public class IntervalStats { packageToken, event.mPackage, event.mNotificationChannelId); } break; + case LOCUS_ID_SET: + if (!TextUtils.isEmpty(event.mLocusId)) { + event.mLocusIdToken = packagesTokenData.getTokenOrAdd(packageToken, + event.mPackage, event.mLocusId); + } + break; } } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java index fe5da923597e..e4aa9fe0dc1e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java +++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java @@ -277,6 +277,10 @@ final class UsageStatsProtoV2 { event.mTaskRootClassToken = proto.readInt( EventObfuscatedProto.TASK_ROOT_CLASS_TOKEN) - 1; break; + case (int) EventObfuscatedProto.LOCUS_ID_TOKEN: + event.mLocusIdToken = proto.readInt( + EventObfuscatedProto.LOCUS_ID_TOKEN) - 1; + break; case ProtoInputStream.NO_MORE_FIELDS: // timeStamp was not read, assume default value 0 plus beginTime if (event.mTimeStamp == 0) { @@ -398,6 +402,11 @@ final class UsageStatsProtoV2 { proto.write(EventObfuscatedProto.SHORTCUT_ID_TOKEN, event.mShortcutIdToken + 1); } break; + case UsageEvents.Event.LOCUS_ID_SET: + if (event.mLocusIdToken != PackagesTokenData.UNASSIGNED_TOKEN) { + proto.write(EventObfuscatedProto.LOCUS_ID_TOKEN, event.mLocusIdToken + 1); + } + break; case UsageEvents.Event.NOTIFICATION_INTERRUPTION: if (event.mNotificationChannelIdToken != PackagesTokenData.UNASSIGNED_TOKEN) { proto.write(EventObfuscatedProto.NOTIFICATION_CHANNEL_ID_TOKEN, diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 5119e5824f7f..9a18f8cd3a46 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -21,6 +21,7 @@ import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE; import static android.app.usage.UsageEvents.Event.DEVICE_EVENT_PACKAGE_NAME; import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN; import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK; +import static android.app.usage.UsageEvents.Event.LOCUS_ID_SET; import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION; import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION; import static android.app.usage.UsageEvents.Event.USER_STOPPED; @@ -30,6 +31,8 @@ import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVIT import android.Manifest; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.IUidObserver; @@ -52,6 +55,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.LocusId; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -1987,6 +1991,17 @@ public class UsageStatsService extends SystemService implements } @Override + public void reportLocusUpdate(@NonNull ComponentName activity, @UserIdInt int userId, + @Nullable LocusId locusId, @NonNull IBinder appToken) { + Event event = new Event(LOCUS_ID_SET, SystemClock.elapsedRealtime()); + event.mLocusId = locusId.getId(); + event.mPackage = activity.getPackageName(); + event.mClass = activity.getClassName(); + event.mInstanceId = appToken.hashCode(); + reportEventOrAddToQueue(userId, event); + } + + @Override public void reportContentProviderUsage(String name, String packageName, int userId) { mAppStandby.postReportContentProviderUsage(name, packageName, userId); } diff --git a/services/usb/java/com/android/server/usb/UsbPermissionManager.java b/services/usb/java/com/android/server/usb/UsbPermissionManager.java index 1e46f981f117..5d3ed4fc6acf 100644 --- a/services/usb/java/com/android/server/usb/UsbPermissionManager.java +++ b/services/usb/java/com/android/server/usb/UsbPermissionManager.java @@ -58,8 +58,8 @@ class UsbPermissionManager { synchronized (mPermissionsByUser) { UsbUserPermissionManager permissions = mPermissionsByUser.get(userId); if (permissions == null) { - permissions = new UsbUserPermissionManager(mContext, UserHandle.of(userId), - mUsbService.getSettingsForUser(userId)); + permissions = new UsbUserPermissionManager(mContext.createContextAsUser( + UserHandle.of(userId), 0), mUsbService.getSettingsForUser(userId)); mPermissionsByUser.put(userId, permissions); } return permissions; diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java index 2a94393b8009..333edfd91b16 100644 --- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java +++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java @@ -109,16 +109,16 @@ class UsbUserPermissionManager { @GuardedBy("mLock") private boolean mIsCopyPermissionsScheduled; - UsbUserPermissionManager(@NonNull Context context, @NonNull UserHandle user, + UsbUserPermissionManager(@NonNull Context context, @NonNull UsbUserSettingsManager usbUserSettingsManager) { mContext = context; - mUser = user; + mUser = context.getUser(); mUsbUserSettingsManager = usbUserSettingsManager; mDisablePermissionDialogs = context.getResources().getBoolean( com.android.internal.R.bool.config_disableUsbPermissionDialogs); mPermissionsFile = new AtomicFile(new File( - Environment.getUserSystemDirectory(user.getIdentifier()), + Environment.getUserSystemDirectory(mUser.getIdentifier()), "usb_permissions.xml"), "usb-permissions"); synchronized (mLock) { diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java index bebbbd01fd88..0093843c4a27 100644 --- a/telecomm/java/android/telecom/DisconnectCause.java +++ b/telecomm/java/android/telecom/DisconnectCause.java @@ -80,20 +80,17 @@ public final class DisconnectCause implements Parcelable { * Reason code (returned via {@link #getReason()}) which indicates that a call could not be * completed because the cellular radio is off or out of service, the device is connected to * a wifi network, but the user has not enabled wifi calling. - * @hide */ public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF"; /** * Reason code (returned via {@link #getReason()}), which indicates that the video telephony * call was disconnected because IMS access is blocked. - * @hide */ public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED"; /** * Reason code, which indicates that the conference call is simulating single party conference. - * @hide */ public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL"; diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java index 2b9213ba9dbc..b8ad9e2fbe6c 100644 --- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java +++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java @@ -258,27 +258,6 @@ public class ParcelableCallAnalytics implements Parcelable { public static final int SIP_PHONE = 0x8; public static final int THIRD_PARTY_PHONE = 0x10; - /** - * Indicating the call source is not specified. - * - * @hide - */ - public static final int CALL_SOURCE_UNSPECIFIED = 0; - - /** - * Indicating the call is initiated via emergency dialer's dialpad. - * - * @hide - */ - public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; - - /** - * Indicating the call is initiated via emergency dialer's shortcut button. - * - * @hide - */ - public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; - public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5; public static final long MILLIS_IN_1_SECOND = 1000; @@ -343,7 +322,7 @@ public class ParcelableCallAnalytics implements Parcelable { private List<VideoEvent> videoEvents; // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants. - private int callSource = CALL_SOURCE_UNSPECIFIED; + private int callSource = TelecomManager.CALL_SOURCE_UNSPECIFIED; public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType, boolean isAdditionalCall, boolean isInterrupted, int callTechnologies, diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index abb210f13376..f00432b5fad3 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -50,6 +50,7 @@ public final class PhoneAccount implements Parcelable { * {@link android.telecom.ConnectionService}. * @hide */ + @SystemApi public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER"; @@ -79,10 +80,13 @@ public final class PhoneAccount implements Parcelable { public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING"; - /** - * Indicating flag for phone account whether to use voip audio mode for voip calls + /** + * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which + * indicates that all calls from this {@link PhoneAccount} should be treated as VoIP calls + * rather than cellular calls. * @hide */ + @SystemApi public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE"; @@ -107,6 +111,7 @@ public final class PhoneAccount implements Parcelable { * * @hide */ + @SystemApi public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK"; @@ -155,6 +160,7 @@ public final class PhoneAccount implements Parcelable { * in progress. * @hide */ + @SystemApi public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE"; @@ -249,6 +255,7 @@ public final class PhoneAccount implements Parcelable { * See {@link #getCapabilities} * @hide */ + @SystemApi public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80; /** @@ -272,6 +279,7 @@ public final class PhoneAccount implements Parcelable { * convert all outgoing video calls to emergency numbers to audio-only. * @hide */ + @SystemApi public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200; /** @@ -329,6 +337,7 @@ public final class PhoneAccount implements Parcelable { * * @hide */ + @SystemApi public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000; /** diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 49b74c6061f4..bf4dee2c1f04 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -313,15 +313,18 @@ public class TelecomManager { "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL"; /** + * A mandatory extra containing a {@link Uri} to be passed in when calling + * {@link #addNewUnknownCall(PhoneAccountHandle, Bundle)}. The {@link Uri} value indicates + * the remote handle of the new call. * @hide */ + @SystemApi public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE"; /** * Optional extra for incoming and outgoing calls containing a long which specifies the time the * call was created. This value is in milliseconds since boot. - * @hide */ public static final String EXTRA_CALL_CREATED_TIME_MILLIS = "android.telecom.extra.CALL_CREATED_TIME_MILLIS"; @@ -366,10 +369,18 @@ public class TelecomManager { "android.telecom.extra.CONNECTION_SERVICE"; /** - * Optional extra for communicating the call technology used by a - * {@link com.android.internal.telephony.Connection} to Telecom + * Optional extra for communicating the call technology used by a {@link ConnectionService} + * to Telecom. Valid values are: + * <ul> + * <li>{@link TelephonyManager#PHONE_TYPE_CDMA}</li> + * <li>{@link TelephonyManager#PHONE_TYPE_GSM}</li> + * <li>{@link TelephonyManager#PHONE_TYPE_IMS}</li> + * <li>{@link TelephonyManager#PHONE_TYPE_THIRD_PARTY}</li> + * <li>{@link TelephonyManager#PHONE_TYPE_SIP}</li> + * </ul> * @hide */ + @SystemApi public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE"; @@ -712,21 +723,24 @@ public class TelecomManager { * @see #EXTRA_CURRENT_TTY_MODE * @hide */ + @SystemApi public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED"; /** * The lookup key for an int that indicates the current TTY mode. * Valid modes are: - * - {@link #TTY_MODE_OFF} - * - {@link #TTY_MODE_FULL} - * - {@link #TTY_MODE_HCO} - * - {@link #TTY_MODE_VCO} - * + * <ul> + * <li>{@link #TTY_MODE_OFF}</li> + * <li>{@link #TTY_MODE_FULL}</li> + * <li>{@link #TTY_MODE_HCO}</li> + * <li>{@link #TTY_MODE_VCO}</li> + * </ul> * @hide */ + @SystemApi public static final String EXTRA_CURRENT_TTY_MODE = - "android.telecom.intent.extra.CURRENT_TTY_MODE"; + "android.telecom.extra.CURRENT_TTY_MODE"; /** * Broadcast intent action indicating that the TTY preferred operating mode has changed. An @@ -735,6 +749,7 @@ public class TelecomManager { * @see #EXTRA_TTY_PREFERRED_MODE * @hide */ + @SystemApi public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED"; @@ -745,8 +760,9 @@ public class TelecomManager { * * @hide */ + @SystemApi public static final String EXTRA_TTY_PREFERRED_MODE = - "android.telecom.intent.extra.TTY_PREFERRED"; + "android.telecom.extra.TTY_PREFERRED_MODE"; /** * Broadcast intent action for letting custom component know to show the missed call @@ -815,16 +831,41 @@ public class TelecomManager { /** * Optional extra for {@link #placeCall(Uri, Bundle)} containing an integer that specifies * the source where user initiated this call. This data is used in metrics. - * Valid source are: - * {@link ParcelableCallAnalytics#CALL_SOURCE_UNSPECIFIED}, - * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_DIALPAD}, - * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_SHORTCUT}. + * Valid sources are: + * {@link TelecomManager#CALL_SOURCE_UNSPECIFIED}, + * {@link TelecomManager#CALL_SOURCE_EMERGENCY_DIALPAD}, + * {@link TelecomManager#CALL_SOURCE_EMERGENCY_SHORTCUT}. * * @hide */ + @SystemApi public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE"; /** + * Indicating the call is initiated via emergency dialer's shortcut button. + * + * @hide + */ + @SystemApi + public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; + + /** + * Indicating the call is initiated via emergency dialer's dialpad. + * + * @hide + */ + @SystemApi + public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; + + /** + * Indicating the call source is not specified. + * + * @hide + */ + @SystemApi + public static final int CALL_SOURCE_UNSPECIFIED = 0; + + /** * The following 4 constants define how properties such as phone numbers and names are * displayed to the user. */ diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index 56c342ee72ca..553bcff931d2 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -20,12 +20,10 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.RemoteException; import android.os.UserHandle; -import android.permission.IPermissionManager; +import android.permission.PermissionManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -76,7 +74,6 @@ public final class CarrierAppUtils { * privileged apps may have changed. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, TelephonyManager telephonyManager, int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); @@ -87,14 +84,14 @@ public final class CarrierAppUtils { ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); ContentResolver contentResolver = getContentResolverForUser(context, userId); - disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager, - telephonyManager, contentResolver, userId, systemCarrierAppsDisabledUntilUsed, - systemCarrierAssociatedAppsDisabledUntilUsed); + disableCarrierAppsUntilPrivileged(callingPackage, telephonyManager, contentResolver, + userId, systemCarrierAppsDisabledUntilUsed, + systemCarrierAssociatedAppsDisabledUntilUsed, context); } /** - * Like {@link #disableCarrierAppsUntilPrivileged(String, IPackageManager, TelephonyManager, - * ContentResolver, int)}, but assumes that no carrier apps have carrier privileges. + * Like {@link #disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, Context)}, + * but assumes that no carrier apps have carrier privileges. * * This prevents a potential race condition on first boot - since the app's default state is * enabled, we will initially disable it when the telephony stack is first initialized as it has @@ -104,8 +101,7 @@ public final class CarrierAppUtils { * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, int userId, - Context context) { + int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -113,13 +109,12 @@ public final class CarrierAppUtils { ArraySet<String> systemCarrierAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierApps(); - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed = config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps(); ContentResolver contentResolver = getContentResolverForUser(context, userId); - disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager, - null /* telephonyManager */, contentResolver, userId, - systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed); + disableCarrierAppsUntilPrivileged(callingPackage, null /* telephonyManager */, + contentResolver, userId, systemCarrierAppsDisabledUntilUsed, + systemCarrierAssociatedAppsDisabledUntilUsed, context); } private static ContentResolver getContentResolverForUser(Context context, int userId) { @@ -135,21 +130,21 @@ public final class CarrierAppUtils { // Must be public b/c framework unit tests can't access package-private methods. @VisibleForTesting public static void disableCarrierAppsUntilPrivileged(String callingPackage, - IPackageManager packageManager, IPermissionManager permissionManager, - @Nullable TelephonyManager telephonyManager, - ContentResolver contentResolver, int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed, - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) { + @Nullable TelephonyManager telephonyManager, ContentResolver contentResolver, + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, + ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed, + Context context) { + PackageManager packageManager = context.getPackageManager(); + PermissionManager permissionManager = + (PermissionManager) context.getSystemService(Context.PERMISSION_SERVICE); List<ApplicationInfo> candidates = getDefaultNotUpdatedCarrierAppCandidatesHelper( - packageManager, userId, systemCarrierAppsDisabledUntilUsed); + userId, systemCarrierAppsDisabledUntilUsed, context); if (candidates == null || candidates.isEmpty()) { return; } Map<String, List<ApplicationInfo>> associatedApps = getDefaultCarrierAssociatedAppsHelper( - packageManager, - userId, - systemCarrierAssociatedAppsDisabledUntilUsed); + userId, systemCarrierAssociatedAppsDisabledUntilUsed, context); List<String> enabledCarrierPackages = new ArrayList<>(); boolean hasRunOnce = Settings.Secure.getInt(contentResolver, @@ -166,19 +161,18 @@ public final class CarrierAppUtils { && !ArrayUtils.contains(restrictedCarrierApps, packageName); // add hiddenUntilInstalled flag for carrier apps and associated apps - packageManager.setSystemAppHiddenUntilInstalled(packageName, true); + packageManager.setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); List<ApplicationInfo> associatedAppList = associatedApps.get(packageName); if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - packageManager.setSystemAppHiddenUntilInstalled( - associatedApp.packageName, - true - ); + packageManager.setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN); } } - int enabledSetting = packageManager.getApplicationEnabledSetting(packageName, - userId); + int enabledSetting = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager().getApplicationEnabledSetting(packageName); if (hasPrivileges) { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. @@ -189,24 +183,25 @@ public final class CarrierAppUtils { || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { Log.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); - packageManager.setSystemAppInstallState( - packageName, - true /*installed*/, - userId); - packageManager.setApplicationEnabledSetting( - packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP, - userId, - callingPackage); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_INSTALLED); + context.createPackageContextAsUser(callingPackage, 0, UserHandle.of(userId)) + .getPackageManager() + .setApplicationEnabledSetting( + packageName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); } // Also enable any associated apps for this carrier app. if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - int associatedAppEnabledSetting = - packageManager.getApplicationEnabledSetting( - associatedApp.packageName, userId); + int associatedAppEnabledSetting = context + .createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationEnabledSetting(associatedApp.packageName); if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || associatedAppEnabledSetting @@ -215,16 +210,17 @@ public final class CarrierAppUtils { & ApplicationInfo.FLAG_INSTALLED) == 0) { Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): ENABLED for user " + userId); - packageManager.setSystemAppInstallState( - associatedApp.packageName, - true /*installed*/, - userId); - packageManager.setApplicationEnabledSetting( - associatedApp.packageName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP, - userId, - callingPackage); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_INSTALLED); + context.createPackageContextAsUser( + callingPackage, 0, UserHandle.of(userId)) + .getPackageManager() + .setApplicationEnabledSetting( + associatedApp.packageName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); } } } @@ -239,10 +235,10 @@ public final class CarrierAppUtils { && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { Log.i(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setSystemAppInstallState( - packageName, - false /*installed*/, - userId); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState( + packageName, PackageManager.SYSTEM_APP_STATE_UNINSTALLED); } // Also disable any associated apps for this carrier app if this is the first @@ -251,9 +247,10 @@ public final class CarrierAppUtils { if (!hasRunOnce) { if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - int associatedAppEnabledSetting = - packageManager.getApplicationEnabledSetting( - associatedApp.packageName, userId); + int associatedAppEnabledSetting = context + .createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationEnabledSetting(associatedApp.packageName); if (associatedAppEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (associatedApp.flags @@ -261,10 +258,10 @@ public final class CarrierAppUtils { Log.i(TAG, "Update associated state(" + associatedApp.packageName + "): DISABLED_UNTIL_USED for user " + userId); - packageManager.setSystemAppInstallState( - associatedApp.packageName, - false /*installed*/, - userId); + context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .setSystemAppState(associatedApp.packageName, + PackageManager.SYSTEM_APP_STATE_UNINSTALLED); } } } @@ -282,9 +279,10 @@ public final class CarrierAppUtils { // apps. String[] packageNames = new String[enabledCarrierPackages.size()]; enabledCarrierPackages.toArray(packageNames); - permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId); + permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, + UserHandle.of(userId), Runnable::run, isSuccess -> { }); } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } } @@ -293,13 +291,13 @@ public final class CarrierAppUtils { * Returns the list of "default" carrier apps. * * This is the subset of apps returned by - * {@link #getDefaultCarrierAppCandidates(IPackageManager, int)} which currently have carrier + * {@link #getDefaultCarrierAppCandidates(int, Context)} which currently have carrier * privileges per the SIM(s) inserted in the device. */ - public static List<ApplicationInfo> getDefaultCarrierApps(IPackageManager packageManager, - TelephonyManager telephonyManager, int userId) { + public static List<ApplicationInfo> getDefaultCarrierApps( + TelephonyManager telephonyManager, int userId, Context context) { // Get all system apps from the default list. - List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(packageManager, userId); + List<ApplicationInfo> candidates = getDefaultCarrierAppCandidates(userId, context); if (candidates == null || candidates.isEmpty()) { return null; } @@ -325,25 +323,23 @@ public final class CarrierAppUtils { * Returns the list of "default" carrier app candidates. * * These are the apps subject to the hiding/showing logic in - * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, IPackageManager, - * TelephonyManager, ContentResolver, int)}, as well as the apps which should have default + * {@link CarrierAppUtils#disableCarrierAppsUntilPrivileged(String, TelephonyManager, int, + * Context)}, as well as the apps which should have default * permissions granted, when a matching SIM is inserted. * * Whether or not the app is actually considered a default app depends on whether the app has * carrier privileges as determined by the SIMs in the device. */ public static List<ApplicationInfo> getDefaultCarrierAppCandidates( - IPackageManager packageManager, int userId) { + int userId, Context context) { ArraySet<String> systemCarrierAppsDisabledUntilUsed = SystemConfig.getInstance().getDisabledUntilUsedPreinstalledCarrierApps(); - return getDefaultCarrierAppCandidatesHelper(packageManager, userId, - systemCarrierAppsDisabledUntilUsed); + return getDefaultCarrierAppCandidatesHelper(userId, systemCarrierAppsDisabledUntilUsed, + context); } private static List<ApplicationInfo> getDefaultCarrierAppCandidatesHelper( - IPackageManager packageManager, - int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed) { + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, Context context) { if (systemCarrierAppsDisabledUntilUsed == null) { return null; } @@ -357,7 +353,7 @@ public final class CarrierAppUtils { for (int i = 0; i < size; i++) { String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i); ApplicationInfo ai = - getApplicationInfoIfSystemApp(packageManager, userId, packageName); + getApplicationInfoIfSystemApp(userId, packageName, context); if (ai != null) { apps.add(ai); } @@ -366,9 +362,7 @@ public final class CarrierAppUtils { } private static List<ApplicationInfo> getDefaultNotUpdatedCarrierAppCandidatesHelper( - IPackageManager packageManager, - int userId, - ArraySet<String> systemCarrierAppsDisabledUntilUsed) { + int userId, ArraySet<String> systemCarrierAppsDisabledUntilUsed, Context context) { if (systemCarrierAppsDisabledUntilUsed == null) { return null; } @@ -382,7 +376,7 @@ public final class CarrierAppUtils { for (int i = 0; i < size; i++) { String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i); ApplicationInfo ai = - getApplicationInfoIfNotUpdatedSystemApp(packageManager, userId, packageName); + getApplicationInfoIfNotUpdatedSystemApp(userId, packageName, context); if (ai != null) { apps.add(ai); } @@ -391,9 +385,8 @@ public final class CarrierAppUtils { } private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper( - IPackageManager packageManager, - int userId, - ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) { + int userId, ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed, + Context context) { int size = systemCarrierAssociatedAppsDisabledUntilUsed.size(); Map<String, List<ApplicationInfo>> associatedApps = new ArrayMap<>(size); for (int i = 0; i < size; i++) { @@ -403,7 +396,7 @@ public final class CarrierAppUtils { for (int j = 0; j < associatedAppPackages.size(); j++) { ApplicationInfo ai = getApplicationInfoIfNotUpdatedSystemApp( - packageManager, userId, associatedAppPackages.get(j)); + userId, associatedAppPackages.get(j), context); // Only update enabled state for the app on /system. Once it has been updated we // shouldn't touch it. if (ai != null) { @@ -421,19 +414,19 @@ public final class CarrierAppUtils { @Nullable private static ApplicationInfo getApplicationInfoIfNotUpdatedSystemApp( - IPackageManager packageManager, - int userId, - String packageName) { + int userId, String packageName, Context context) { try { - ApplicationInfo ai = packageManager.getApplicationInfo(packageName, - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS - | PackageManager.MATCH_SYSTEM_ONLY - | PackageManager.MATCH_FACTORY_ONLY, userId); + ApplicationInfo ai = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationInfo(packageName, + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.MATCH_FACTORY_ONLY); if (ai != null) { return ai; } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } return null; @@ -441,18 +434,18 @@ public final class CarrierAppUtils { @Nullable private static ApplicationInfo getApplicationInfoIfSystemApp( - IPackageManager packageManager, - int userId, - String packageName) { + int userId, String packageName, Context context) { try { - ApplicationInfo ai = packageManager.getApplicationInfo(packageName, - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS - | PackageManager.MATCH_SYSTEM_ONLY, userId); + ApplicationInfo ai = context.createContextAsUser(UserHandle.of(userId), 0) + .getPackageManager() + .getApplicationInfo(packageName, + PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_SYSTEM_ONLY); if (ai != null) { return ai; } - } catch (RemoteException e) { + } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Could not reach PackageManager", e); } return null; diff --git a/core/java/android/service/euicc/IEuiccServiceDumpResultCallback.aidl b/telephony/java/android/service/euicc/IEuiccServiceDumpResultCallback.aidl index ea55ebbadd88..ea55ebbadd88 100644 --- a/core/java/android/service/euicc/IEuiccServiceDumpResultCallback.aidl +++ b/telephony/java/android/service/euicc/IEuiccServiceDumpResultCallback.aidl diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index b30f5868cc63..945c8888f402 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4230,26 +4230,26 @@ public class CarrierConfigManager { sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, // Boundaries: [-140 dB, -44 dB] new int[] { - -125, /* SIGNAL_STRENGTH_POOR */ - -115, /* SIGNAL_STRENGTH_MODERATE */ - -105, /* SIGNAL_STRENGTH_GOOD */ - -95, /* SIGNAL_STRENGTH_GREAT */ + -110, /* SIGNAL_STRENGTH_POOR */ + -90, /* SIGNAL_STRENGTH_MODERATE */ + -80, /* SIGNAL_STRENGTH_GOOD */ + -65, /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, // Boundaries: [-20 dB, -3 dB] new int[] { - -14, /* SIGNAL_STRENGTH_POOR */ - -12, /* SIGNAL_STRENGTH_MODERATE */ - -10, /* SIGNAL_STRENGTH_GOOD */ - -8 /* SIGNAL_STRENGTH_GREAT */ + -16, /* SIGNAL_STRENGTH_POOR */ + -11, /* SIGNAL_STRENGTH_MODERATE */ + -9, /* SIGNAL_STRENGTH_GOOD */ + -7 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, // Boundaries: [-23 dB, 40 dB] new int[] { - -8, /* SIGNAL_STRENGTH_POOR */ - 0, /* SIGNAL_STRENGTH_MODERATE */ - 8, /* SIGNAL_STRENGTH_GOOD */ - 16 /* SIGNAL_STRENGTH_GREAT */ + -5, /* SIGNAL_STRENGTH_POOR */ + 5, /* SIGNAL_STRENGTH_MODERATE */ + 15, /* SIGNAL_STRENGTH_GOOD */ + 30 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP); diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index 4d67bcf536cf..f4c13fff9943 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -45,28 +45,28 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa // Lifted from Default carrier configs and max range of SSRSRP // Boundaries: [-140 dB, -44 dB] private int[] mSsRsrpThresholds = new int[] { - -125, /* SIGNAL_STRENGTH_POOR */ - -115, /* SIGNAL_STRENGTH_MODERATE */ - -105, /* SIGNAL_STRENGTH_GOOD */ - -95, /* SIGNAL_STRENGTH_GREAT */ + -110, /* SIGNAL_STRENGTH_POOR */ + -90, /* SIGNAL_STRENGTH_MODERATE */ + -80, /* SIGNAL_STRENGTH_GOOD */ + -65, /* SIGNAL_STRENGTH_GREAT */ }; // Lifted from Default carrier configs and max range of SSRSRQ // Boundaries: [-20 dB, -3 dB] private int[] mSsRsrqThresholds = new int[] { - -14, /* SIGNAL_STRENGTH_POOR */ - -12, /* SIGNAL_STRENGTH_MODERATE */ - -10, /* SIGNAL_STRENGTH_GOOD */ - -8 /* SIGNAL_STRENGTH_GREAT */ + -16, /* SIGNAL_STRENGTH_POOR */ + -11, /* SIGNAL_STRENGTH_MODERATE */ + -9, /* SIGNAL_STRENGTH_GOOD */ + -7 /* SIGNAL_STRENGTH_GREAT */ }; // Lifted from Default carrier configs and max range of SSSINR // Boundaries: [-23 dB, 40 dB] private int[] mSsSinrThresholds = new int[] { - -8, /* SIGNAL_STRENGTH_POOR */ - 0, /* SIGNAL_STRENGTH_MODERATE */ - 8, /* SIGNAL_STRENGTH_GOOD */ - 16 /* SIGNAL_STRENGTH_GREAT */ + -5, /* SIGNAL_STRENGTH_POOR */ + 5, /* SIGNAL_STRENGTH_MODERATE */ + 15, /* SIGNAL_STRENGTH_GOOD */ + 30 /* SIGNAL_STRENGTH_GREAT */ }; /** diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index 9b4292f42172..704e5aa78188 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -27,11 +27,7 @@ import android.telephony.SubscriptionManager; /** * Provides access to information about Telephony IMS services on the device. - * - * @hide */ -@SystemApi -@TestApi @SystemService(Context.TELEPHONY_IMS_SERVICE) public class ImsManager { @@ -45,7 +41,10 @@ public class ImsManager { * <p class="note"> * Carrier applications may listen to this broadcast to be notified of possible IMS provisioning * issues. + * @hide */ + @SystemApi + @TestApi // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have // this value hard-coded in BroadcastReceiver. @SuppressLint("ActionValue") @@ -104,7 +103,10 @@ public class ImsManager { * @param subscriptionId The ID of the subscription that this ImsRcsManager will use. * @throws IllegalArgumentException if the subscription is invalid. * @return a ImsRcsManager instance with the specific subscription ID. + * @hide */ + @SystemApi + @TestApi @NonNull public ImsRcsManager getImsRcsManager(int subscriptionId) { if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 1e64a8182e3b..5b09cd9e6caa 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -317,6 +317,14 @@ public class ServiceState implements Parcelable { */ public static final int UNKNOWN_ID = -1; + /** + * A parcelable extra used with {@link Intent#ACTION_SERVICE_STATE} representing the service + * state. + * @hide + */ + private static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE"; + + private String mOperatorAlphaLong; private String mOperatorAlphaShort; private String mOperatorNumeric; @@ -1292,7 +1300,7 @@ public class ServiceState implements Parcelable { */ @UnsupportedAppUsage private void setFromNotifierBundle(Bundle m) { - ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE); + ServiceState ssFromBundle = m.getParcelable(EXTRA_SERVICE_STATE); if (ssFromBundle != null) { copyFrom(ssFromBundle); } @@ -1310,7 +1318,7 @@ public class ServiceState implements Parcelable { */ @SystemApi public void fillInNotifierBundle(@NonNull Bundle m) { - m.putParcelable(Intent.EXTRA_SERVICE_STATE, this); + m.putParcelable(EXTRA_SERVICE_STATE, this); // serviceState already consists of below entries. // for backward compatibility, we continue fill in below entries. m.putInt("voiceRegState", mVoiceRegState); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1d89665c1670..86913a636913 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7348,6 +7348,30 @@ public class TelephonyManager { } } + + /** + * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot. + * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to + * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad + * state. + * + * @param slotIndex the sim slot to reset the IMS stack on. + * @hide */ + @SystemApi + @WorkerThread + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void resetIms(int slotIndex) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.resetIms(slotIndex); + } + } catch (RemoteException e) { + Rlog.e(TAG, "toggleImsOnOff, RemoteException: " + + e.getMessage()); + } + } + /** * Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability * status updates, if not already enabled. diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index cb3f0f92625e..643f452d2e75 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -61,7 +61,6 @@ public final class ImsException extends Exception { * This is a configuration error and there should be no retry. The subscription used for this * operation is either invalid or has become inactive. The active subscriptions can be queried * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}. - * @hide */ public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 5fdef8307d42..3341fa74d672 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -56,7 +56,8 @@ import java.util.function.Consumer; * registration and MmTel capability status callbacks, as well as query/modify user settings for the * associated subscription. * - * @see #createForSubscriptionId(int) + * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this + * manager. */ public class ImsMmTelManager implements RegistrationManager { @@ -228,8 +229,13 @@ public class ImsMmTelManager implements RegistrationManager { * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). * * @throws IllegalArgumentException if the subscription is invalid. - * + * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an + * instance of this class. + * @hide */ + @SystemApi + @TestApi + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(anyOf = { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, @@ -245,7 +251,7 @@ public class ImsMmTelManager implements RegistrationManager { } /** - * Only visible for testing, use {@link #createForSubscriptionId(int)} instead. + * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead. * @hide */ @VisibleForTesting @@ -255,7 +261,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link RegistrationCallback} with the system, which will provide registration - * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use + * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * @@ -453,7 +459,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service * availability updates for the subscription specified in - * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)} + * {@link ImsManager#getImsMmTelManager(int)}. The method {@see #isAvailable(int, int)} * can also be used to query this information at any time. * * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 62bc2ae44573..2b3072eefe2e 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -60,9 +60,10 @@ import com.android.internal.annotations.VisibleForTesting; * The telephony framework will then bind to the ImsService you have defined in your manifest * if you are either: * 1) Defined as the default ImsService for the device in the device overlay using - * "config_ims_package". + * "config_ims_mmtel_package" or "config_ims_rcs_package". * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using - * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}. + * {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or + * {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}. * * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService} * supports, dynamic or static definitions. diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java deleted file mode 100644 index e90548a4445f..000000000000 --- a/telephony/java/android/telephony/ims/Rcs1To1Thread.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.WorkerThread; - -/** - * Rcs1To1Thread represents a single RCS conversation thread with a total of two - * {@link RcsParticipant}s. Please see Section 5 (1-to-1 Messaging) - GSMA RCC.71 (RCS Universal - * Profile Service Definition Document) - * - * @hide - */ -public class Rcs1To1Thread extends RcsThread { - private int mThreadId; - - /** - * Public constructor only for RcsMessageStoreController to initialize new threads. - * - * @hide - */ - public Rcs1To1Thread(RcsControllerCall rcsControllerCall, int threadId) { - super(rcsControllerCall, threadId); - mThreadId = threadId; - } - - /** - * @return Returns {@code false} as this is always a 1 to 1 thread. - */ - @Override - public boolean isGroup() { - return false; - } - - /** - * {@link Rcs1To1Thread}s can fall back to SMS as a back-up protocol. This function returns the - * thread id to be used to query {@code content://mms-sms/conversation/#} to get the fallback - * thread. - * - * @return The thread id to be used to query the mms-sms authority - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getFallbackThreadId() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.get1To1ThreadFallbackThreadId(mThreadId, - callingPackage)); - } - - /** - * If the RCS client allows falling back to SMS, it needs to create an MMS-SMS thread in the - * SMS/MMS Provider( see {@link android.provider.Telephony.MmsSms#CONTENT_CONVERSATIONS_URI}. - * Use this function to link the {@link Rcs1To1Thread} to the MMS-SMS thread. This function - * also updates the storage. - * - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setFallbackThreadId(long fallbackThreadId) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.set1To1ThreadFallbackThreadId(mThreadId, - fallbackThreadId, callingPackage)); - } - - /** - * @return Returns the {@link RcsParticipant} that receives the messages sent in this thread. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @NonNull - @WorkerThread - public RcsParticipant getRecipient() throws RcsMessageStoreException { - return new RcsParticipant( - mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.get1To1ThreadOtherParticipantId(mThreadId, - callingPackage))); - } -} diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 3e2903fa6f47..57b9b7a30f8c 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -16,10 +16,11 @@ package android.telephony.ims; -import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -37,6 +38,7 @@ import java.util.Map; * @hide */ @SystemApi +@TestApi public final class RcsContactUceCapability implements Parcelable { /** Supports 1-to-1 chat */ @@ -99,11 +101,16 @@ public final class RcsContactUceCapability implements Parcelable { public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27); /** Supports the unidirectional plug-ins framework. */ public static final int CAPABILITY_PLUG_IN = (1 << 28); + /** Supports standalone Chatbot communication. */ + public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29); + /** Supports MMTEL based call composer. */ + public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30); + /** @hide*/ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "CAPABILITY_", flag = true, value = { + @LongDef(prefix = "CAPABILITY_", flag = true, value = { CAPABILITY_CHAT_STANDALONE, CAPABILITY_CHAT_SESSION, CAPABILITY_CHAT_SESSION_STORE_FORWARD, @@ -132,7 +139,9 @@ public final class RcsContactUceCapability implements Parcelable { CAPABILITY_SHARED_SKETCH, CAPABILITY_CHAT_BOT, CAPABILITY_CHAT_BOT_ROLE, - CAPABILITY_PLUG_IN + CAPABILITY_PLUG_IN, + CAPABILITY_STANDALONE_CHAT_BOT, + CAPABILITY_MMTEL_CALL_COMPOSER }) public @interface CapabilityFlag {} @@ -159,11 +168,11 @@ public final class RcsContactUceCapability implements Parcelable { * @param type The capability to map to a service URI that is different from the contact's * URI. */ - public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) { + public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) { mCapabilities.mCapabilities |= type; // Put each of these capabilities into the map separately. - for (int shift = 0; shift < Integer.SIZE; shift++) { - int cap = type & (1 << shift); + for (long shift = 0; shift < Integer.SIZE; shift++) { + long cap = type & (1 << shift); if (cap != 0) { mCapabilities.mServiceMap.put(cap, serviceUri); // remove that capability from the field. @@ -181,7 +190,7 @@ public final class RcsContactUceCapability implements Parcelable { * Add a UCE capability flag that this contact supports. * @param type the capability that the contact supports. */ - public @NonNull Builder add(@CapabilityFlag int type) { + public @NonNull Builder add(@CapabilityFlag long type) { mCapabilities.mCapabilities |= type; return this; } @@ -207,7 +216,7 @@ public final class RcsContactUceCapability implements Parcelable { private final Uri mContactUri; private long mCapabilities; private List<String> mExtensionTags = new ArrayList<>(); - private Map<Integer, Uri> mServiceMap = new HashMap<>(); + private Map<Long, Uri> mServiceMap = new HashMap<>(); /** * Use {@link Builder} to build an instance of this interface. @@ -225,7 +234,7 @@ public final class RcsContactUceCapability implements Parcelable { // read mServiceMap as key,value pair int mapSize = in.readInt(); for (int i = 0; i < mapSize; i++) { - mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader())); + mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader())); } } @@ -250,8 +259,8 @@ public final class RcsContactUceCapability implements Parcelable { // write mServiceMap as key,value pairs int mapSize = mServiceMap.keySet().size(); out.writeInt(mapSize); - for (int key : mServiceMap.keySet()) { - out.writeInt(key); + for (long key : mServiceMap.keySet()) { + out.writeLong(key); out.writeParcelable(mServiceMap.get(key), 0); } } @@ -266,7 +275,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param type The capability flag to query. * @return true if the capability flag specified is set, false otherwise. */ - public boolean isCapable(@CapabilityFlag int type) { + public boolean isCapable(@CapabilityFlag long type) { return (mCapabilities & type) > 0; } @@ -290,13 +299,13 @@ public final class RcsContactUceCapability implements Parcelable { * <p> * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless * a different service {@link Uri} was associated with this capability using - * {@link Builder#add(int, Uri)}. + * {@link Builder#add(long, Uri)}. * * @return a String containing the {@link Uri} associated with the service tag or * {@code null} if this capability is not set as capable. - * @see #isCapable(int) + * @see #isCapable(long) */ - public @Nullable Uri getServiceUri(@CapabilityFlag int type) { + public @Nullable Uri getServiceUri(@CapabilityFlag long type) { Uri result = mServiceMap.getOrDefault(type, null); // If the capability is capable, but does not have a service URI associated, use the default // contact URI. diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java deleted file mode 100644 index 1e93437a5a94..000000000000 --- a/telephony/java/android/telephony/ims/RcsControllerCall.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.content.Context; -import android.os.RemoteException; -import android.telephony.TelephonyFrameworkInitializer; -import android.telephony.ims.aidl.IRcsMessage; - -/** - * A wrapper class around RPC calls that {@link RcsMessageManager} APIs to minimize boilerplate - * code. - * - * @hide - not meant for public use - */ -class RcsControllerCall { - private final Context mContext; - - RcsControllerCall(Context context) { - mContext = context; - } - - <R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException { - IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getTelephonyRcsMessageServiceRegisterer() - .get()); - if (iRcsMessage == null) { - throw new RcsMessageStoreException("Could not connect to RCS storage service"); - } - - try { - return serviceCall.methodOnIRcs(iRcsMessage, mContext.getOpPackageName()); - } catch (RemoteException exception) { - throw new RcsMessageStoreException(exception.getMessage()); - } - } - - void callWithNoReturn(RcsServiceCallWithNoReturn serviceCall) - throws RcsMessageStoreException { - call((iRcsMessage, callingPackage) -> { - serviceCall.methodOnIRcs(iRcsMessage, callingPackage); - return null; - }); - } - - interface RcsServiceCall<R> { - R methodOnIRcs(IRcsMessage iRcs, String callingPackage) throws RemoteException; - } - - interface RcsServiceCallWithNoReturn { - void methodOnIRcs(IRcsMessage iRcs, String callingPackage) throws RemoteException; - } -} diff --git a/telephony/java/android/telephony/ims/RcsEvent.java b/telephony/java/android/telephony/ims/RcsEvent.java deleted file mode 100644 index 9dd07209fcfd..000000000000 --- a/telephony/java/android/telephony/ims/RcsEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -/** - * The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s. - * - * @hide - */ -public abstract class RcsEvent { - private final long mTimestamp; - - protected RcsEvent(long timestamp) { - mTimestamp = timestamp; - } - - /** - * @return Returns the time of when this event happened. The timestamp is defined as - * milliseconds passed after midnight, January 1, 1970 UTC - */ - public long getTimestamp() { - return mTimestamp; - } - - /** - * Persists the event to the data store - * - * @hide - */ - abstract void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException; -} diff --git a/telephony/java/android/telephony/ims/RcsEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsEventDescriptor.aidl deleted file mode 100644 index ab1c55ec984f..000000000000 --- a/telephony/java/android/telephony/ims/RcsEventDescriptor.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsEventDescriptor.java b/telephony/java/android/telephony/ims/RcsEventDescriptor.java deleted file mode 100644 index b44adeaa62bb..000000000000 --- a/telephony/java/android/telephony/ims/RcsEventDescriptor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public abstract class RcsEventDescriptor implements Parcelable { - protected final long mTimestamp; - - RcsEventDescriptor(long timestamp) { - mTimestamp = timestamp; - } - - /** - * Creates an RcsEvent based on this RcsEventDescriptor. Overriding this method practically - * allows an injection point for RcsEvent dependencies outside of the values contained in the - * descriptor. - */ - @VisibleForTesting(visibility = PROTECTED) - public abstract RcsEvent createRcsEvent(RcsControllerCall rcsControllerCall); - - RcsEventDescriptor(Parcel in) { - mTimestamp = in.readLong(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mTimestamp); - } - - @Override - public int describeContents() { - return 0; - } -} diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.java b/telephony/java/android/telephony/ims/RcsEventQueryParams.java deleted file mode 100644 index 0024cf7b8662..000000000000 --- a/telephony/java/android/telephony/ims/RcsEventQueryParams.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import static android.provider.Telephony.RcsColumns.RcsEventTypes.ICON_CHANGED_EVENT_TYPE; -import static android.provider.Telephony.RcsColumns.RcsEventTypes.NAME_CHANGED_EVENT_TYPE; -import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE; -import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_JOINED_EVENT_TYPE; -import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_LEFT_EVENT_TYPE; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.InvalidParameterException; - -/** - * The parameters to pass into - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} in order to select a - * subset of {@link RcsEvent}s present in the message store. - * - * @hide - */ -public final class RcsEventQueryParams implements Parcelable { - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return all types of - * {@link RcsEvent}s - */ - public static final int ALL_EVENTS = -1; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return sub-types of - * {@link RcsGroupThreadEvent}s - */ - public static final int ALL_GROUP_THREAD_EVENTS = 0; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only - * {@link RcsParticipantAliasChangedEvent}s - */ - public static final int PARTICIPANT_ALIAS_CHANGED_EVENT = - PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only - * {@link RcsGroupThreadParticipantJoinedEvent}s - */ - public static final int GROUP_THREAD_PARTICIPANT_JOINED_EVENT = - PARTICIPANT_JOINED_EVENT_TYPE; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only - * {@link RcsGroupThreadParticipantLeftEvent}s - */ - public static final int GROUP_THREAD_PARTICIPANT_LEFT_EVENT = - PARTICIPANT_LEFT_EVENT_TYPE; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only - * {@link RcsGroupThreadNameChangedEvent}s - */ - public static final int GROUP_THREAD_NAME_CHANGED_EVENT = NAME_CHANGED_EVENT_TYPE; - - /** - * Flag to be used with {@link Builder#setEventType(int)} to make - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only - * {@link RcsGroupThreadIconChangedEvent}s - */ - public static final int GROUP_THREAD_ICON_CHANGED_EVENT = ICON_CHANGED_EVENT_TYPE; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ALL_EVENTS, ALL_GROUP_THREAD_EVENTS, PARTICIPANT_ALIAS_CHANGED_EVENT, - GROUP_THREAD_PARTICIPANT_JOINED_EVENT, GROUP_THREAD_PARTICIPANT_LEFT_EVENT, - GROUP_THREAD_NAME_CHANGED_EVENT, GROUP_THREAD_ICON_CHANGED_EVENT}) - public @interface EventType { - } - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} that makes the result set sorted - * in the order of creation for faster query results. - */ - public static final int SORT_BY_CREATION_ORDER = 0; - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} that makes the result set sorted - * with respect to {@link RcsEvent#getTimestamp()} - */ - public static final int SORT_BY_TIMESTAMP = 1; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP}) - public @interface SortingProperty { - } - - /** - * The key to pass into a Bundle, for usage in RcsProvider.query(Bundle) - * @hide - not meant for public use - */ - public static final String EVENT_QUERY_PARAMETERS_KEY = "event_query_parameters"; - - // Which types of events the results should be limited to - private @EventType int mEventType; - // The property which the results should be sorted against - private int mSortingProperty; - // Whether the results should be sorted in ascending order - private boolean mIsAscending; - // The number of results that should be returned with this query - private int mLimit; - // The thread that the results are limited to - private int mThreadId; - - RcsEventQueryParams(@EventType int eventType, int threadId, - @SortingProperty int sortingProperty, boolean isAscending, int limit) { - mEventType = eventType; - mSortingProperty = sortingProperty; - mIsAscending = isAscending; - mLimit = limit; - mThreadId = threadId; - } - - /** - * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParams} is - * set to query for. - */ - public @EventType int getEventType() { - return mEventType; - } - - /** - * @return Returns the number of {@link RcsEvent}s to be returned from the query. A value of - * 0 means there is no set limit. - */ - public int getLimit() { - return mLimit; - } - - /** - * @return Returns the property where the results should be sorted against. - * @see SortingProperty - */ - public int getSortingProperty() { - return mSortingProperty; - } - - /** - * @return Returns {@code true} if the result set will be sorted in ascending order, - * {@code false} if it will be sorted in descending order. - */ - public boolean getSortDirection() { - return mIsAscending; - } - - /** - * @return Returns the ID of the {@link RcsGroupThread} that the results are limited to. As this - * API exposes an ID, it should stay hidden. - * - * @hide - */ - public int getThreadId() { - return mThreadId; - } - - /** - * A helper class to build the {@link RcsEventQueryParams}. - */ - public static class Builder { - private @EventType int mEventType; - private @SortingProperty int mSortingProperty; - private boolean mIsAscending; - private int mLimit = 100; - private int mThreadId; - - /** - * Creates a new builder for {@link RcsEventQueryParams} to be used in - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} - */ - public Builder() { - // empty implementation - } - - /** - * Desired number of events to be returned from the query. Passing in 0 will return all - * existing events at once. The limit defaults to 100. - * - * @param limit The number to limit the query result to. - * @return The same instance of the builder to chain parameters. - * @throws InvalidParameterException If the given limit is negative. - */ - @CheckResult - public Builder setResultLimit(@IntRange(from = 0) int limit) - throws InvalidParameterException { - if (limit < 0) { - throw new InvalidParameterException("The query limit must be non-negative"); - } - - mLimit = limit; - return this; - } - - /** - * Sets the type of events to be returned from the query. - * - * @param eventType The type of event to be returned. - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setEventType(@EventType int eventType) { - mEventType = eventType; - return this; - } - - /** - * Sets the property where the results should be sorted against. Defaults to - * {@link RcsEventQueryParams.SortingProperty#SORT_BY_CREATION_ORDER} - * - * @param sortingProperty against which property the results should be sorted - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortProperty(@SortingProperty int sortingProperty) { - mSortingProperty = sortingProperty; - return this; - } - - /** - * Sets whether the results should be sorted ascending or descending - * - * @param isAscending whether the results should be sorted ascending - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortDirection(boolean isAscending) { - mIsAscending = isAscending; - return this; - } - - /** - * Limits the results to the given {@link RcsGroupThread}. Setting this value prevents - * returning any instances of {@link RcsParticipantAliasChangedEvent}. - * - * @param groupThread The thread to limit the results to. - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setGroupThread(@NonNull RcsGroupThread groupThread) { - mThreadId = groupThread.getThreadId(); - return this; - } - - /** - * Builds the {@link RcsEventQueryParams} to use in - * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} - * - * @return An instance of {@link RcsEventQueryParams} to use with the event query. - */ - public RcsEventQueryParams build() { - return new RcsEventQueryParams(mEventType, mThreadId, mSortingProperty, - mIsAscending, mLimit); - } - } - - private RcsEventQueryParams(Parcel in) { - mEventType = in.readInt(); - mThreadId = in.readInt(); - mSortingProperty = in.readInt(); - mIsAscending = in.readBoolean(); - mLimit = in.readInt(); - } - - public static final @android.annotation.NonNull Creator<RcsEventQueryParams> CREATOR = - new Creator<RcsEventQueryParams>() { - @Override - public RcsEventQueryParams createFromParcel(Parcel in) { - return new RcsEventQueryParams(in); - } - - @Override - public RcsEventQueryParams[] newArray(int size) { - return new RcsEventQueryParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mEventType); - dest.writeInt(mThreadId); - dest.writeInt(mSortingProperty); - dest.writeBoolean(mIsAscending); - dest.writeInt(mLimit); - } -} diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java deleted file mode 100644 index d6347e3ec693..000000000000 --- a/telephony/java/android/telephony/ims/RcsEventQueryResult.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import java.util.List; - -/** - * The result of a {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} - * call. This class allows getting the token for querying the next batch of events in order to - * prevent handling large amounts of data at once. - * - * @hide - */ -public class RcsEventQueryResult { - private RcsQueryContinuationToken mContinuationToken; - private List<RcsEvent> mEvents; - - /** - * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController} - * to create query results - * - * @hide - */ - public RcsEventQueryResult( - RcsQueryContinuationToken continuationToken, - List<RcsEvent> events) { - mContinuationToken = continuationToken; - mEvents = events; - } - - /** - * Returns a token to call - * {@link RcsMessageStore#getRcsEvents(RcsQueryContinuationToken)} - * to get the next batch of {@link RcsEvent}s. - */ - public RcsQueryContinuationToken getContinuationToken() { - return mContinuationToken; - } - - /** - * Returns all the {@link RcsEvent}s in the current query result. Call {@link - * RcsMessageStore#getRcsEvents(RcsQueryContinuationToken)} to get the next batch - * of {@link RcsEvent}s. - */ - public List<RcsEvent> getEvents() { - return mEvents; - } -} diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java b/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java deleted file mode 100644 index b972d557fae0..000000000000 --- a/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Contains the raw data backing a {@link RcsEventQueryResult}. - * - * @hide - used only for internal communication with the ircs service - */ -public class RcsEventQueryResultDescriptor implements Parcelable { - private final RcsQueryContinuationToken mContinuationToken; - private final List<RcsEventDescriptor> mEvents; - - public RcsEventQueryResultDescriptor( - RcsQueryContinuationToken continuationToken, - List<RcsEventDescriptor> events) { - mContinuationToken = continuationToken; - mEvents = events; - } - - protected RcsEventQueryResult getRcsEventQueryResult(RcsControllerCall rcsControllerCall) { - List<RcsEvent> rcsEvents = mEvents.stream() - .map(rcsEvent -> rcsEvent.createRcsEvent(rcsControllerCall)) - .collect(Collectors.toList()); - - return new RcsEventQueryResult(mContinuationToken, rcsEvents); - } - - protected RcsEventQueryResultDescriptor(Parcel in) { - mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader()); - mEvents = new LinkedList<>(); - in.readList(mEvents, null); - } - - public static final @android.annotation.NonNull Creator<RcsEventQueryResultDescriptor> CREATOR = - new Creator<RcsEventQueryResultDescriptor>() { - @Override - public RcsEventQueryResultDescriptor createFromParcel(Parcel in) { - return new RcsEventQueryResultDescriptor(in); - } - - @Override - public RcsEventQueryResultDescriptor[] newArray(int size) { - return new RcsEventQueryResultDescriptor[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mContinuationToken, flags); - dest.writeList(mEvents); - } -} diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java deleted file mode 100644 index e43552d74bf3..000000000000 --- a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.CheckResult; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Pass an instance of this class to - * {@link RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)} create an - * {@link RcsFileTransferPart} and save it into storage. - * - * @hide - */ -public final class RcsFileTransferCreationParams implements Parcelable { - private String mRcsFileTransferSessionId; - private Uri mContentUri; - private String mContentMimeType; - private long mFileSize; - private long mTransferOffset; - private int mWidth; - private int mHeight; - private long mMediaDuration; - private Uri mPreviewUri; - private String mPreviewMimeType; - private @RcsFileTransferPart.RcsFileTransferStatus int mFileTransferStatus; - - /** - * @return Returns the globally unique RCS file transfer session ID for the - * {@link RcsFileTransferPart} to be created - */ - public String getRcsFileTransferSessionId() { - return mRcsFileTransferSessionId; - } - - /** - * @return Returns the URI for the content of the {@link RcsFileTransferPart} to be created - */ - public Uri getContentUri() { - return mContentUri; - } - - /** - * @return Returns the MIME type for the content of the {@link RcsFileTransferPart} to be - * created - */ - public String getContentMimeType() { - return mContentMimeType; - } - - /** - * @return Returns the file size in bytes for the {@link RcsFileTransferPart} to be created - */ - public long getFileSize() { - return mFileSize; - } - - /** - * @return Returns the transfer offset for the {@link RcsFileTransferPart} to be created. The - * file transfer offset is defined as how many bytes have been successfully transferred to the - * receiver of this file transfer. - */ - public long getTransferOffset() { - return mTransferOffset; - } - - /** - * @return Returns the width of the {@link RcsFileTransferPart} to be created. The value is in - * pixels. - */ - public int getWidth() { - return mWidth; - } - - /** - * @return Returns the height of the {@link RcsFileTransferPart} to be created. The value is in - * pixels. - */ - public int getHeight() { - return mHeight; - } - - /** - * @return Returns the duration of the {@link RcsFileTransferPart} to be created. - */ - public long getMediaDuration() { - return mMediaDuration; - } - - /** - * @return Returns the URI of the preview of the content of the {@link RcsFileTransferPart} to - * be created. This should only be used for multi-media files. - */ - public Uri getPreviewUri() { - return mPreviewUri; - } - - /** - * @return Returns the MIME type of the preview of the content of the - * {@link RcsFileTransferPart} to be created. This should only be used for multi-media files. - */ - public String getPreviewMimeType() { - return mPreviewMimeType; - } - - /** - * @return Returns the status of the {@link RcsFileTransferPart} to be created. - */ - public @RcsFileTransferPart.RcsFileTransferStatus int getFileTransferStatus() { - return mFileTransferStatus; - } - - /** - * @hide - */ - RcsFileTransferCreationParams(Builder builder) { - mRcsFileTransferSessionId = builder.mRcsFileTransferSessionId; - mContentUri = builder.mContentUri; - mContentMimeType = builder.mContentMimeType; - mFileSize = builder.mFileSize; - mTransferOffset = builder.mTransferOffset; - mWidth = builder.mWidth; - mHeight = builder.mHeight; - mMediaDuration = builder.mLength; - mPreviewUri = builder.mPreviewUri; - mPreviewMimeType = builder.mPreviewMimeType; - mFileTransferStatus = builder.mFileTransferStatus; - } - - /** - * A builder to create instances of {@link RcsFileTransferCreationParams} - */ - public class Builder { - private String mRcsFileTransferSessionId; - private Uri mContentUri; - private String mContentMimeType; - private long mFileSize; - private long mTransferOffset; - private int mWidth; - private int mHeight; - private long mLength; - private Uri mPreviewUri; - private String mPreviewMimeType; - private @RcsFileTransferPart.RcsFileTransferStatus int mFileTransferStatus; - - /** - * Sets the globally unique RCS file transfer session ID for the {@link RcsFileTransferPart} - * to be created - * - * @param sessionId The RCS file transfer session ID - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setFileTransferSessionId(String sessionId) { - mRcsFileTransferSessionId = sessionId; - return this; - } - - /** - * Sets the URI for the content of the {@link RcsFileTransferPart} to be created - * - * @param contentUri The URI for the file - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setContentUri(Uri contentUri) { - mContentUri = contentUri; - return this; - } - - /** - * Sets the MIME type for the content of the {@link RcsFileTransferPart} to be created - * - * @param contentType The MIME type of the file - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setContentMimeType(String contentType) { - mContentMimeType = contentType; - return this; - } - - /** - * Sets the file size for the {@link RcsFileTransferPart} to be created - * - * @param size The size of the file in bytes - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setFileSize(long size) { - mFileSize = size; - return this; - } - - /** - * Sets the transfer offset for the {@link RcsFileTransferPart} to be created. The file - * transfer offset is defined as how many bytes have been successfully transferred to the - * receiver of this file transfer. - * - * @param offset The transfer offset in bytes - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setTransferOffset(long offset) { - mTransferOffset = offset; - return this; - } - - /** - * Sets the width of the {@link RcsFileTransferPart} to be created. This should only be used - * for multi-media files. - * - * @param width The width of the multi-media file in pixels. - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setWidth(int width) { - mWidth = width; - return this; - } - - /** - * Sets the height of the {@link RcsFileTransferPart} to be created. This should only be - * used for multi-media files. - * - * @param height The height of the multi-media file in pixels. - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setHeight(int height) { - mHeight = height; - return this; - } - - /** - * Sets the length of the {@link RcsFileTransferPart} to be created. This should only be - * used for multi-media files such as audio or video. - * - * @param length The length of the multi-media file in milliseconds - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setMediaDuration(long length) { - mLength = length; - return this; - } - - /** - * Sets the URI of the preview of the content of the {@link RcsFileTransferPart} to be - * created. This should only be used for multi-media files. - * - * @param previewUri The URI of the preview of the file transfer - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setPreviewUri(Uri previewUri) { - mPreviewUri = previewUri; - return this; - } - - /** - * Sets the MIME type of the preview of the content of the {@link RcsFileTransferPart} to - * be created. This should only be used for multi-media files. - * - * @param previewType The MIME type of the preview of the file transfer - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setPreviewMimeType(String previewType) { - mPreviewMimeType = previewType; - return this; - } - - /** - * Sets the status of the {@link RcsFileTransferPart} to be created. - * - * @param status The status of the file transfer - * @return The same instance of {@link Builder} to chain methods - */ - @CheckResult - public Builder setFileTransferStatus( - @RcsFileTransferPart.RcsFileTransferStatus int status) { - mFileTransferStatus = status; - return this; - } - - /** - * Creates an instance of {@link RcsFileTransferCreationParams} with the given - * parameters. - * - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#insertFileTransfer(RcsFileTransferCreationParams) - */ - public RcsFileTransferCreationParams build() { - return new RcsFileTransferCreationParams(this); - } - } - - private RcsFileTransferCreationParams(Parcel in) { - mRcsFileTransferSessionId = in.readString(); - mContentUri = in.readParcelable(Uri.class.getClassLoader()); - mContentMimeType = in.readString(); - mFileSize = in.readLong(); - mTransferOffset = in.readLong(); - mWidth = in.readInt(); - mHeight = in.readInt(); - mMediaDuration = in.readLong(); - mPreviewUri = in.readParcelable(Uri.class.getClassLoader()); - mPreviewMimeType = in.readString(); - mFileTransferStatus = in.readInt(); - } - - public static final @android.annotation.NonNull Creator<RcsFileTransferCreationParams> CREATOR = - new Creator<RcsFileTransferCreationParams>() { - @Override - public RcsFileTransferCreationParams createFromParcel(Parcel in) { - return new RcsFileTransferCreationParams(in); - } - - @Override - public RcsFileTransferCreationParams[] newArray(int size) { - return new RcsFileTransferCreationParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mRcsFileTransferSessionId); - dest.writeParcelable(mContentUri, flags); - dest.writeString(mContentMimeType); - dest.writeLong(mFileSize); - dest.writeLong(mTransferOffset); - dest.writeInt(mWidth); - dest.writeInt(mHeight); - dest.writeLong(mMediaDuration); - dest.writeParcelable(mPreviewUri, flags); - dest.writeString(mPreviewMimeType); - dest.writeInt(mFileTransferStatus); - } -} diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java deleted file mode 100644 index ef66a76a5902..000000000000 --- a/telephony/java/android/telephony/ims/RcsFileTransferPart.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.IntDef; -import android.annotation.Nullable; -import android.annotation.WorkerThread; -import android.net.Uri; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * A part of a composite {@link RcsMessage} that holds a file transfer. Please see Section 7 - * (File Transfer) - GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public class RcsFileTransferPart { - /** - * The status to indicate that this {@link RcsFileTransferPart} is not set yet. - */ - public static final int NOT_SET = 0; - - /** - * The status to indicate that this {@link RcsFileTransferPart} is a draft and is not in the - * process of sending yet. - */ - public static final int DRAFT = 1; - - /** - * The status to indicate that this {@link RcsFileTransferPart} is actively being sent right - * now. - */ - public static final int SENDING = 2; - - /** - * The status to indicate that this {@link RcsFileTransferPart} was being sent, but the user has - * paused the sending process. - */ - public static final int SENDING_PAUSED = 3; - - /** - * The status to indicate that this {@link RcsFileTransferPart} was attempted, but failed to - * send. - */ - public static final int SENDING_FAILED = 4; - - /** - * The status to indicate that this {@link RcsFileTransferPart} is permanently cancelled to - * send. - */ - public static final int SENDING_CANCELLED = 5; - - /** - * The status to indicate that this {@link RcsFileTransferPart} is actively being downloaded - * right now. - */ - public static final int DOWNLOADING = 6; - - /** - * The status to indicate that this {@link RcsFileTransferPart} was being downloaded, but the - * user paused the downloading process. - */ - public static final int DOWNLOADING_PAUSED = 7; - - /** - * The status to indicate that this {@link RcsFileTransferPart} was attempted, but failed to - * download. - */ - public static final int DOWNLOADING_FAILED = 8; - - /** - * The status to indicate that this {@link RcsFileTransferPart} is permanently cancelled to - * download. - */ - public static final int DOWNLOADING_CANCELLED = 9; - - /** - * The status to indicate that this {@link RcsFileTransferPart} was successfully sent or - * received. - */ - public static final int SUCCEEDED = 10; - - @IntDef({ - DRAFT, SENDING, SENDING_PAUSED, SENDING_FAILED, SENDING_CANCELLED, DOWNLOADING, - DOWNLOADING_PAUSED, DOWNLOADING_FAILED, DOWNLOADING_CANCELLED, SUCCEEDED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RcsFileTransferStatus { - } - - private final RcsControllerCall mRcsControllerCall; - - private int mId; - - /** - * @hide - */ - RcsFileTransferPart(RcsControllerCall rcsControllerCall, int id) { - mRcsControllerCall = rcsControllerCall; - mId = id; - } - - /** - * @hide - */ - public void setId(int id) { - mId = id; - } - - /** - * @hide - */ - public int getId() { - return mId; - } - - /** - * Sets the RCS file transfer session ID for this file transfer and persists into storage. - * - * @param sessionId The session ID to be used for this file transfer. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setFileTransferSessionId(String sessionId) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferSessionId(mId, sessionId, - callingPackage)); - } - - /** - * @return Returns the file transfer session ID. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public String getFileTransferSessionId() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferSessionId(mId, callingPackage)); - } - - /** - * Sets the content URI for this file transfer and persists into storage. The file transfer - * should be reachable using this URI. - * - * @param contentUri The URI for this file transfer. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setContentUri(Uri contentUri) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferContentUri(mId, contentUri, - callingPackage)); - } - - /** - * @return Returns the URI for this file transfer - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public Uri getContentUri() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferContentUri(mId, callingPackage)); - } - - /** - * Sets the MIME type of this file transfer and persists into storage. Whether this type - * actually matches any known or supported types is not checked. - * - * @param contentMimeType The type of this file transfer. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setContentMimeType(String contentMimeType) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferContentType(mId, contentMimeType, - callingPackage)); - } - - /** - * @return Returns the content type of this file transfer - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - @Nullable - public String getContentMimeType() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferContentType(mId, callingPackage)); - } - - /** - * Sets the content length (i.e. file size) for this file transfer and persists into storage. - * - * @param contentLength The content length of this file transfer - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setFileSize(long contentLength) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferFileSize(mId, contentLength, - callingPackage)); - } - - /** - * @return Returns the content length (i.e. file size) for this file transfer. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getFileSize() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferFileSize(mId, callingPackage)); - } - - /** - * Sets the transfer offset for this file transfer and persists into storage. The file transfer - * offset is defined as how many bytes have been successfully transferred to the receiver of - * this file transfer. - * - * @param transferOffset The transfer offset for this file transfer. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setTransferOffset(long transferOffset) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferTransferOffset(mId, transferOffset, - callingPackage)); - } - - /** - * @return Returns the number of bytes that have successfully transferred. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getTransferOffset() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferTransferOffset(mId, callingPackage)); - } - - /** - * Sets the status for this file transfer and persists into storage. - * - * @param status The status of this file transfer. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setFileTransferStatus(@RcsFileTransferStatus int status) - throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferStatus(mId, status, callingPackage)); - } - - /** - * @return Returns the status of this file transfer. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public @RcsFileTransferStatus int getFileTransferStatus() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferStatus(mId, callingPackage)); - } - - /** - * @return Returns the width of this multi-media message part in pixels. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public int getWidth() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferWidth(mId, callingPackage)); - } - - /** - * Sets the width of this RCS multi-media message part and persists into storage. - * - * @param width The width value in pixels - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setWidth(int width) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferWidth(mId, width, callingPackage)); - } - - /** - * @return Returns the height of this multi-media message part in pixels. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public int getHeight() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferHeight(mId, callingPackage)); - } - - /** - * Sets the height of this RCS multi-media message part and persists into storage. - * - * @param height The height value in pixels - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setHeight(int height) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferHeight(mId, height, callingPackage)); - } - - /** - * @return Returns the length of this multi-media file (e.g. video or audio) in milliseconds. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getLength() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferLength(mId, callingPackage)); - } - - /** - * Sets the length of this multi-media file (e.g. video or audio) and persists into storage. - * - * @param length The length of the file in milliseconds. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setLength(long length) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferLength(mId, length, callingPackage)); - } - - /** - * @return Returns the URI for the preview of this multi-media file (e.g. an image thumbnail for - * a video) - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public Uri getPreviewUri() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferPreviewUri(mId, callingPackage)); - } - - /** - * Sets the URI for the preview of this multi-media file and persists into storage. - * - * @param previewUri The URI to access to the preview file. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setPreviewUri(Uri previewUri) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferPreviewUri(mId, previewUri, - callingPackage)); - } - - /** - * @return Returns the MIME type of this multi-media file's preview. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public String getPreviewMimeType() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransferPreviewType(mId, callingPackage)); - } - - /** - * Sets the MIME type for this multi-media file's preview and persists into storage. - * - * @param previewMimeType The MIME type for the preview - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setPreviewMimeType(String previewMimeType) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setFileTransferPreviewType(mId, previewMimeType, - callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java deleted file mode 100644 index 30abcb4abb3d..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThread.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.WorkerThread; -import android.net.Uri; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -/** - * RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join - * or leave. Please see Section 6 (Group Chat) - GSMA RCC.71 (RCS Universal Profile Service - * Definition Document) - * - * @hide - */ -public class RcsGroupThread extends RcsThread { - /** - * Public constructor only for RcsMessageStoreController to initialize new threads. - * - * @hide - */ - public RcsGroupThread(RcsControllerCall rcsControllerCall, int threadId) { - super(rcsControllerCall, threadId); - } - - /** - * @return Returns {@code true} as this is always a group thread - */ - @Override - public boolean isGroup() { - return true; - } - - /** - * @return Returns the given name of this {@link RcsGroupThread}. Please see US6-2 - GSMA RCC.71 - * (RCS Universal Profile Service Definition Document) - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public String getGroupName() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getGroupThreadName(mThreadId, callingPackage)); - } - - /** - * Sets the name of this {@link RcsGroupThread} and saves it into storage. Please see US6-2 - - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setGroupName(String groupName) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setGroupThreadName(mThreadId, groupName, - callingPackage)); - } - - /** - * @return Returns a URI that points to the group's icon {@link RcsGroupThread}. Please see - * US6-2 - GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - public Uri getGroupIcon() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getGroupThreadIcon(mThreadId, callingPackage)); - } - - /** - * Sets the icon for this {@link RcsGroupThread} and saves it into storage. Please see US6-2 - - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setGroupIcon(@Nullable Uri groupIcon) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setGroupThreadIcon(mThreadId, groupIcon, - callingPackage)); - } - - /** - * @return Returns the owner of this thread or {@code null} if there doesn't exist an owner - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public RcsParticipant getOwner() throws RcsMessageStoreException { - return new RcsParticipant( - mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getGroupThreadOwner(mThreadId, - callingPackage))); - } - - /** - * Sets the owner of this {@link RcsGroupThread} and saves it into storage. This is intended to - * be used for selecting a new owner for a group thread if the owner leaves the thread. The - * owner needs to be in the list of existing participants. - * - * @param participant The new owner of the thread. {@code null} values are allowed. - * @throws RcsMessageStoreException if the operation could not be persisted into storage - */ - @WorkerThread - public void setOwner(@Nullable RcsParticipant participant) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setGroupThreadOwner(mThreadId, participant.getId(), - callingPackage)); - } - - /** - * Adds a new {@link RcsParticipant} to this group thread and persists into storage. If the user - * is actively participating in this {@link RcsGroupThread}, an {@link RcsParticipant} on behalf - * of them should be added. - * - * @param participant The new participant to be added to the thread. - * @throws RcsMessageStoreException if the operation could not be persisted into storage - */ - @WorkerThread - public void addParticipant(@NonNull RcsParticipant participant) - throws RcsMessageStoreException { - if (participant == null) { - return; - } - - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.addParticipantToGroupThread(mThreadId, - participant.getId(), callingPackage)); - } - - /** - * Removes an {@link RcsParticipant} from this group thread and persists into storage. If the - * removed participant was the owner of this group, the owner will become null. - * - * @throws RcsMessageStoreException if the operation could not be persisted into storage - */ - @WorkerThread - public void removeParticipant(@NonNull RcsParticipant participant) - throws RcsMessageStoreException { - if (participant == null) { - return; - } - - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.removeParticipantFromGroupThread(mThreadId, - participant.getId(), callingPackage)); - } - - /** - * Returns the set of {@link RcsParticipant}s that contribute to this group thread. The - * returned set does not support modifications, please use - * {@link RcsGroupThread#addParticipant(RcsParticipant)} - * and {@link RcsGroupThread#removeParticipant(RcsParticipant)} instead. - * - * @return the immutable set of {@link RcsParticipant} in this group thread. - * @throws RcsMessageStoreException if the values could not be read from the storage - */ - @WorkerThread - @NonNull - public Set<RcsParticipant> getParticipants() throws RcsMessageStoreException { - RcsParticipantQueryParams queryParameters = - new RcsParticipantQueryParams.Builder().setThread(this).build(); - - RcsParticipantQueryResult queryResult = new RcsParticipantQueryResult( - mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getParticipants(queryParameters, - callingPackage))); - - List<RcsParticipant> participantList = queryResult.getParticipants(); - Set<RcsParticipant> participantSet = new LinkedHashSet<>(participantList); - return Collections.unmodifiableSet(participantSet); - } - - /** - * Returns the conference URI for this {@link RcsGroupThread}. Please see 4.4.5.2 - GSMA RCC.53 - * (RCS Device API 1.6 Specification - * - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public Uri getConferenceUri() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getGroupThreadConferenceUri(mThreadId, - callingPackage)); - } - - /** - * Sets the conference URI for this {@link RcsGroupThread} and persists into storage. Please see - * 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification - * - * @param conferenceUri The URI as String to be used as the conference URI. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @Nullable - @WorkerThread - public void setConferenceUri(Uri conferenceUri) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setGroupThreadConferenceUri(mThreadId, conferenceUri, - callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java deleted file mode 100644 index f4beef7f9843..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; - -/** - * An event that happened on an {@link RcsGroupThread}. - * - * @hide - */ -public abstract class RcsGroupThreadEvent extends RcsEvent { - private final RcsGroupThread mRcsGroupThread; - private final RcsParticipant mOriginatingParticipant; - - RcsGroupThreadEvent(long timestamp, RcsGroupThread rcsGroupThread, - RcsParticipant originatingParticipant) { - super(timestamp); - mRcsGroupThread = rcsGroupThread; - mOriginatingParticipant = originatingParticipant; - } - - /** - * @return Returns the {@link RcsGroupThread} that this event happened on. - */ - @NonNull - public RcsGroupThread getRcsGroupThread() { - return mRcsGroupThread; - } - - /** - * @return Returns the {@link RcsParticipant} that performed the event. - */ - @NonNull - public RcsParticipant getOriginatingParticipant() { - return mOriginatingParticipant; - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl deleted file mode 100644 index 6299d8a5eb71..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsGroupThreadEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java deleted file mode 100644 index 662a264b6d67..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.os.Parcel; - -/** - * @hide - used only for internal communication with the ircs service - */ -public abstract class RcsGroupThreadEventDescriptor extends RcsEventDescriptor { - protected final int mRcsGroupThreadId; - protected final int mOriginatingParticipantId; - - RcsGroupThreadEventDescriptor(long timestamp, int rcsGroupThreadId, - int originatingParticipantId) { - super(timestamp); - mRcsGroupThreadId = rcsGroupThreadId; - mOriginatingParticipantId = originatingParticipantId; - } - - RcsGroupThreadEventDescriptor(Parcel in) { - super(in); - mRcsGroupThreadId = in.readInt(); - mOriginatingParticipantId = in.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(mRcsGroupThreadId); - dest.writeInt(mOriginatingParticipantId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java deleted file mode 100644 index 23e39ffb3680..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.Uri; - -/** - * An event that indicates an {@link RcsGroupThread}'s icon was changed. Please see R6-2-5 - GSMA - * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent { - private final Uri mNewIcon; - - /** - * Creates a new {@link RcsGroupThreadIconChangedEvent}. This event is not persisted into - * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called. - * - * @param timestamp The timestamp of when this event happened, in milliseconds passed after - * midnight, January 1st, 1970 UTC - * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on - * @param originatingParticipant The {@link RcsParticipant} that changed the - * {@link RcsGroupThread}'s icon. - * @param newIcon {@link Uri} to the new icon of this {@link RcsGroupThread} - * @see RcsMessageStore#persistRcsEvent(RcsEvent) - */ - public RcsGroupThreadIconChangedEvent(long timestamp, - @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant, - @Nullable Uri newIcon) { - super(timestamp, rcsGroupThread, originatingParticipant); - mNewIcon = newIcon; - } - - /** - * @return Returns the {@link Uri} to the icon of the {@link RcsGroupThread} after this - * {@link RcsGroupThreadIconChangedEvent} occured. - */ - @Nullable - public Uri getNewIcon() { - return mNewIcon; - } - - /** - * Persists the event to the data store. - * - * @hide - not meant for public use. - */ - @Override - void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException { - // TODO ensure failure throws - rcsControllerCall.call((iRcs, callingPackage) -> iRcs.createGroupThreadIconChangedEvent( - getTimestamp(), getRcsGroupThread().getThreadId(), - getOriginatingParticipant().getId(), mNewIcon, callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl deleted file mode 100644 index 4bcc5a043acd..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsGroupThreadIconChangedEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java deleted file mode 100644 index 9350e402c04e..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.Uri; -import android.os.Parcel; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsGroupThreadIconChangedEventDescriptor extends RcsGroupThreadEventDescriptor { - private final Uri mNewIcon; - - public RcsGroupThreadIconChangedEventDescriptor(long timestamp, int rcsGroupThreadId, - int originatingParticipantId, @Nullable Uri newIcon) { - super(timestamp, rcsGroupThreadId, originatingParticipantId); - mNewIcon = newIcon; - } - - @Override - @VisibleForTesting(visibility = PROTECTED) - public RcsGroupThreadIconChangedEvent createRcsEvent(RcsControllerCall rcsControllerCall) { - return new RcsGroupThreadIconChangedEvent(mTimestamp, - new RcsGroupThread(rcsControllerCall, mRcsGroupThreadId), - new RcsParticipant(rcsControllerCall, mOriginatingParticipantId), mNewIcon); - } - - public static final @NonNull Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR = - new Creator<RcsGroupThreadIconChangedEventDescriptor>() { - @Override - public RcsGroupThreadIconChangedEventDescriptor createFromParcel(Parcel in) { - return new RcsGroupThreadIconChangedEventDescriptor(in); - } - - @Override - public RcsGroupThreadIconChangedEventDescriptor[] newArray(int size) { - return new RcsGroupThreadIconChangedEventDescriptor[size]; - } - }; - - protected RcsGroupThreadIconChangedEventDescriptor(Parcel in) { - super(in); - mNewIcon = in.readParcelable(Uri.class.getClassLoader()); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeParcelable(mNewIcon, flags); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java deleted file mode 100644 index a6a0867ca739..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -/** - * An event that indicates an {@link RcsGroupThread}'s name was changed. Please see R6-2-5 - GSMA - * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent { - private final String mNewName; - - /** - * Creates a new {@link RcsGroupThreadNameChangedEvent}. This event is not persisted into - * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called. - * - * @param timestamp The timestamp of when this event happened, in milliseconds passed after - * midnight, January 1st, 1970 UTC - * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on - * @param originatingParticipant The {@link RcsParticipant} that changed the - * {@link RcsGroupThread}'s icon. - * @param newName The new name of the {@link RcsGroupThread} - * @see RcsMessageStore#persistRcsEvent(RcsEvent) - */ - public RcsGroupThreadNameChangedEvent(long timestamp, @NonNull RcsGroupThread rcsGroupThread, - @NonNull RcsParticipant originatingParticipant, @Nullable String newName) { - super(timestamp, rcsGroupThread, originatingParticipant); - mNewName = newName; - } - - /** - * @return Returns the name of this {@link RcsGroupThread} after this - * {@link RcsGroupThreadNameChangedEvent} happened. - */ - @Nullable - public String getNewName() { - return mNewName; - } - - /** - * Persists the event to the data store. - * - * @hide - not meant for public use. - */ - @Override - void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException { - rcsControllerCall.call((iRcs, callingPackage) -> iRcs.createGroupThreadNameChangedEvent( - getTimestamp(), getRcsGroupThread().getThreadId(), - getOriginatingParticipant().getId(), mNewName, callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl deleted file mode 100644 index 480e86b73ea9..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsGroupThreadNameChangedEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java deleted file mode 100644 index f9ccdd53f0a2..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsGroupThreadNameChangedEventDescriptor extends RcsGroupThreadEventDescriptor { - private final String mNewName; - - public RcsGroupThreadNameChangedEventDescriptor(long timestamp, int rcsGroupThreadId, - int originatingParticipantId, @Nullable String newName) { - super(timestamp, rcsGroupThreadId, originatingParticipantId); - mNewName = newName; - } - - @Override - @VisibleForTesting(visibility = PROTECTED) - public RcsGroupThreadNameChangedEvent createRcsEvent(RcsControllerCall rcsControllerCall) { - return new RcsGroupThreadNameChangedEvent( - mTimestamp, - new RcsGroupThread(rcsControllerCall, mRcsGroupThreadId), - new RcsParticipant(rcsControllerCall, mOriginatingParticipantId), - mNewName); - } - - public static final @NonNull Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR = - new Creator<RcsGroupThreadNameChangedEventDescriptor>() { - @Override - public RcsGroupThreadNameChangedEventDescriptor createFromParcel(Parcel in) { - return new RcsGroupThreadNameChangedEventDescriptor(in); - } - - @Override - public RcsGroupThreadNameChangedEventDescriptor[] newArray(int size) { - return new RcsGroupThreadNameChangedEventDescriptor[size]; - } - }; - - protected RcsGroupThreadNameChangedEventDescriptor(Parcel in) { - super(in); - mNewName = in.readString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(mNewName); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java deleted file mode 100644 index 694c7de96eee..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; - -/** - * An event that indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 - - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent { - private final RcsParticipant mJoinedParticipantId; - - /** - * Creates a new {@link RcsGroupThreadParticipantJoinedEvent}. This event is not persisted into - * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called. - * - * @param timestamp The timestamp of when this event happened, in milliseconds - * passed after - * midnight, January 1st, 1970 UTC - * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on - * @param originatingParticipant The {@link RcsParticipant} that added or invited the new - * {@link RcsParticipant} into the {@link RcsGroupThread} - * @param joinedParticipant The new {@link RcsParticipant} that joined the - * {@link RcsGroupThread} - * @see RcsMessageStore#persistRcsEvent(RcsEvent) - */ - public RcsGroupThreadParticipantJoinedEvent(long timestamp, - @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant, - @NonNull RcsParticipant joinedParticipant) { - super(timestamp, rcsGroupThread, originatingParticipant); - mJoinedParticipantId = joinedParticipant; - } - - /** - * @return Returns the {@link RcsParticipant} that joined the associated {@link RcsGroupThread} - */ - public RcsParticipant getJoinedParticipant() { - return mJoinedParticipantId; - } - - /** - * Persists the event to the data store. - * - * @hide - not meant for public use. - */ - @Override - void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException { - rcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.createGroupThreadParticipantJoinedEvent( - getTimestamp(), - getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(), - getJoinedParticipant().getId(), callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl deleted file mode 100644 index 7210b9f2fab1..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsGroupThreadParticipantJoinedEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java deleted file mode 100644 index 4a6803ebc52c..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.annotation.NonNull; -import android.os.Parcel; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsGroupThreadParticipantJoinedEventDescriptor extends RcsGroupThreadEventDescriptor { - private final int mJoinedParticipantId; - - public RcsGroupThreadParticipantJoinedEventDescriptor(long timestamp, int rcsGroupThreadId, - int originatingParticipantId, int joinedParticipantId) { - super(timestamp, rcsGroupThreadId, originatingParticipantId); - mJoinedParticipantId = joinedParticipantId; - } - - @Override - @VisibleForTesting(visibility = PROTECTED) - public RcsGroupThreadParticipantJoinedEvent createRcsEvent( - RcsControllerCall rcsControllerCall) { - return new RcsGroupThreadParticipantJoinedEvent( - mTimestamp, - new RcsGroupThread(rcsControllerCall, mRcsGroupThreadId), - new RcsParticipant(rcsControllerCall, mOriginatingParticipantId), - new RcsParticipant(rcsControllerCall, mJoinedParticipantId)); - } - - public static final @NonNull Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR = - new Creator<RcsGroupThreadParticipantJoinedEventDescriptor>() { - @Override - public RcsGroupThreadParticipantJoinedEventDescriptor createFromParcel(Parcel in) { - return new RcsGroupThreadParticipantJoinedEventDescriptor(in); - } - - @Override - public RcsGroupThreadParticipantJoinedEventDescriptor[] newArray(int size) { - return new RcsGroupThreadParticipantJoinedEventDescriptor[size]; - } - }; - - protected RcsGroupThreadParticipantJoinedEventDescriptor(Parcel in) { - super(in); - mJoinedParticipantId = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(mJoinedParticipantId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java deleted file mode 100644 index fec4354a293a..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; - -/** - * An event that indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 - - * GSMA RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent { - private RcsParticipant mLeavingParticipant; - - /** - * Creates a new {@link RcsGroupThreadParticipantLeftEvent}. his event is not persisted into - * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called. - * - * @param timestamp The timestamp of when this event happened, in milliseconds passed after - * midnight, January 1st, 1970 UTC - * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on - * @param originatingParticipant The {@link RcsParticipant} that removed the - * {@link RcsParticipant} from the {@link RcsGroupThread}. It is - * possible that originatingParticipant and leavingParticipant are - * the same (i.e. {@link RcsParticipant} left the group - * themselves) - * @param leavingParticipant The {@link RcsParticipant} that left the {@link RcsGroupThread} - * @see RcsMessageStore#persistRcsEvent(RcsEvent) - */ - public RcsGroupThreadParticipantLeftEvent(long timestamp, - @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant, - @NonNull RcsParticipant leavingParticipant) { - super(timestamp, rcsGroupThread, originatingParticipant); - mLeavingParticipant = leavingParticipant; - } - - /** - * @return Returns the {@link RcsParticipant} that left the associated {@link RcsGroupThread} - * after this {@link RcsGroupThreadParticipantLeftEvent} happened. - */ - @NonNull - public RcsParticipant getLeavingParticipant() { - return mLeavingParticipant; - } - - @Override - void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException { - rcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.createGroupThreadParticipantLeftEvent(getTimestamp(), - getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(), - getLeavingParticipant().getId(), callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl deleted file mode 100644 index 3ef921001ce7..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2018, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsGroupThreadParticipantLeftEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java deleted file mode 100644 index 9b1085c3d178..000000000000 --- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsGroupThreadParticipantLeftEventDescriptor extends RcsGroupThreadEventDescriptor { - private int mLeavingParticipantId; - - public RcsGroupThreadParticipantLeftEventDescriptor(long timestamp, int rcsGroupThreadId, - int originatingParticipantId, int leavingParticipantId) { - super(timestamp, rcsGroupThreadId, originatingParticipantId); - mLeavingParticipantId = leavingParticipantId; - } - - @Override - @VisibleForTesting(visibility = PROTECTED) - public RcsGroupThreadParticipantLeftEvent createRcsEvent(RcsControllerCall rcsControllerCall) { - return new RcsGroupThreadParticipantLeftEvent( - mTimestamp, - new RcsGroupThread(rcsControllerCall, mRcsGroupThreadId), - new RcsParticipant(rcsControllerCall, mOriginatingParticipantId), - new RcsParticipant(rcsControllerCall, mLeavingParticipantId)); - } - - @NonNull - public static final Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR = - new Creator<RcsGroupThreadParticipantLeftEventDescriptor>() { - @Override - public RcsGroupThreadParticipantLeftEventDescriptor createFromParcel(Parcel in) { - return new RcsGroupThreadParticipantLeftEventDescriptor(in); - } - - @Override - public RcsGroupThreadParticipantLeftEventDescriptor[] newArray(int size) { - return new RcsGroupThreadParticipantLeftEventDescriptor[size]; - } - }; - - protected RcsGroupThreadParticipantLeftEventDescriptor(Parcel in) { - super(in); - mLeavingParticipantId = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(mLeavingParticipantId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java deleted file mode 100644 index 2810a49927c5..000000000000 --- a/telephony/java/android/telephony/ims/RcsIncomingMessage.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.WorkerThread; - -/** - * This is a single instance of a message received over RCS. - * - * @hide - */ -public class RcsIncomingMessage extends RcsMessage { - /** - * @hide - */ - RcsIncomingMessage(RcsControllerCall rcsControllerCall, int id) { - super(rcsControllerCall, id); - } - - /** - * Sets the timestamp of arrival for this message and persists into storage. The timestamp is - * defined as milliseconds passed after midnight, January 1, 1970 UTC - * - * @param arrivalTimestamp The timestamp to set to. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setArrivalTimestamp(long arrivalTimestamp) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setMessageArrivalTimestamp(mId, true, - arrivalTimestamp, callingPackage)); - } - - /** - * @return Returns the timestamp of arrival for this message. The timestamp is defined as - * milliseconds passed after midnight, January 1, 1970 UTC - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getArrivalTimestamp() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageArrivalTimestamp(mId, true, - callingPackage)); - } - - /** - * Sets the timestamp of when the user saw this message and persists into storage. The timestamp - * is defined as milliseconds passed after midnight, January 1, 1970 UTC - * - * @param notifiedTimestamp The timestamp to set to. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setSeenTimestamp(long notifiedTimestamp) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setMessageSeenTimestamp(mId, true, notifiedTimestamp, - callingPackage)); - } - - /** - * @return Returns the timestamp of when the user saw this message. The timestamp is defined as - * milliseconds passed after midnight, January 1, 1970 UTC - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getSeenTimestamp() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageSeenTimestamp(mId, true, callingPackage)); - } - - /** - * @return Returns the sender of this incoming message. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public RcsParticipant getSenderParticipant() throws RcsMessageStoreException { - return new RcsParticipant( - mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getSenderParticipant(mId, callingPackage))); - } - - /** - * @return Returns {@code true} as this is an incoming message - */ - @Override - public boolean isIncoming() { - return true; - } -} diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl deleted file mode 100644 index 1f1d4f68213a..000000000000 --- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsIncomingMessageCreationParams; diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java deleted file mode 100644 index d95dc4fda3e3..000000000000 --- a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.CheckResult; -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * {@link RcsIncomingMessageCreationParams} is a collection of parameters that should be passed - * into {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} to generate an - * {@link RcsIncomingMessage} on that {@link RcsThread} - * - * @hide - */ -public final class RcsIncomingMessageCreationParams extends RcsMessageCreationParams implements - Parcelable { - // The arrival timestamp for the RcsIncomingMessage to be created - private final long mArrivalTimestamp; - // The seen timestamp for the RcsIncomingMessage to be created - private final long mSeenTimestamp; - // The participant that sent this incoming message - private final int mSenderParticipantId; - - /** - * Builder to help create an {@link RcsIncomingMessageCreationParams} - * - * @see RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams) - */ - public static class Builder extends RcsMessageCreationParams.Builder { - private RcsParticipant mSenderParticipant; - private long mArrivalTimestamp; - private long mSeenTimestamp; - - /** - * Creates a {@link Builder} to create an instance of - * {@link RcsIncomingMessageCreationParams} - * - * @param originationTimestamp The timestamp of {@link RcsMessage} creation. The origination - * timestamp value in milliseconds passed after midnight, - * January 1, 1970 UTC - * @param arrivalTimestamp The timestamp of arrival, defined as milliseconds passed after - * midnight, January 1, 1970 UTC - * @param subscriptionId The subscription ID that was used to send or receive this - * {@link RcsMessage} - */ - public Builder(long originationTimestamp, long arrivalTimestamp, int subscriptionId) { - super(originationTimestamp, subscriptionId); - mArrivalTimestamp = arrivalTimestamp; - } - - /** - * Sets the {@link RcsParticipant} that send this {@link RcsIncomingMessage} - * - * @param senderParticipant The {@link RcsParticipant} that sent this - * {@link RcsIncomingMessage} - * @return The same instance of {@link Builder} to chain methods. - */ - @CheckResult - public Builder setSenderParticipant(RcsParticipant senderParticipant) { - mSenderParticipant = senderParticipant; - return this; - } - - /** - * Sets the time of the arrival of this {@link RcsIncomingMessage} - - * @return The same instance of {@link Builder} to chain methods. - * @see RcsIncomingMessage#setArrivalTimestamp(long) - */ - @CheckResult - public Builder setArrivalTimestamp(long arrivalTimestamp) { - mArrivalTimestamp = arrivalTimestamp; - return this; - } - - /** - * Sets the time of the when this user saw the {@link RcsIncomingMessage} - * @param seenTimestamp The seen timestamp , defined as milliseconds passed after midnight, - * January 1, 1970 UTC - * @return The same instance of {@link Builder} to chain methods. - * @see RcsIncomingMessage#setSeenTimestamp(long) - */ - @CheckResult - public Builder setSeenTimestamp(long seenTimestamp) { - mSeenTimestamp = seenTimestamp; - return this; - } - - /** - * Creates parameters for creating a new incoming message. - * @return A new instance of {@link RcsIncomingMessageCreationParams} to create a new - * {@link RcsIncomingMessage} - */ - public RcsIncomingMessageCreationParams build() { - return new RcsIncomingMessageCreationParams(this); - } - } - - private RcsIncomingMessageCreationParams(Builder builder) { - super(builder); - mArrivalTimestamp = builder.mArrivalTimestamp; - mSeenTimestamp = builder.mSeenTimestamp; - mSenderParticipantId = builder.mSenderParticipant.getId(); - } - - private RcsIncomingMessageCreationParams(Parcel in) { - super(in); - mArrivalTimestamp = in.readLong(); - mSeenTimestamp = in.readLong(); - mSenderParticipantId = in.readInt(); - } - - /** - * @return Returns the arrival timestamp for the {@link RcsIncomingMessage} to be created. - * Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC - */ - public long getArrivalTimestamp() { - return mArrivalTimestamp; - } - - /** - * @return Returns the seen timestamp for the {@link RcsIncomingMessage} to be created. - * Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC - */ - public long getSeenTimestamp() { - return mSeenTimestamp; - } - - /** - * Helper getter for {@link com.android.internal.telephony.ims.RcsMessageStoreController} to - * create {@link RcsIncomingMessage}s - * - * Since the API doesn't expose any ID's to API users, this should be hidden. - * @hide - */ - public int getSenderParticipantId() { - return mSenderParticipantId; - } - - public static final @NonNull Creator<RcsIncomingMessageCreationParams> CREATOR = - new Creator<RcsIncomingMessageCreationParams>() { - @Override - public RcsIncomingMessageCreationParams createFromParcel(Parcel in) { - return new RcsIncomingMessageCreationParams(in); - } - - @Override - public RcsIncomingMessageCreationParams[] newArray(int size) { - return new RcsIncomingMessageCreationParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest); - dest.writeLong(mArrivalTimestamp); - dest.writeLong(mSeenTimestamp); - dest.writeInt(mSenderParticipantId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java deleted file mode 100644 index 4601bfd0ff2c..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessage.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.WorkerThread; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * This is a single instance of a message sent or received over RCS. - * - * @hide - */ -public abstract class RcsMessage { - /** - * The value to indicate that this {@link RcsMessage} does not have any location information. - */ - public static final double LOCATION_NOT_SET = Double.MIN_VALUE; - - /** - * The status to indicate that this {@link RcsMessage}s status is not set yet. - */ - public static final int NOT_SET = 0; - - /** - * The status to indicate that this {@link RcsMessage} is a draft and is not in the process of - * sending yet. - */ - public static final int DRAFT = 1; - - /** - * The status to indicate that this {@link RcsMessage} was successfully sent. - */ - public static final int QUEUED = 2; - - /** - * The status to indicate that this {@link RcsMessage} is actively being sent. - */ - public static final int SENDING = 3; - - /** - * The status to indicate that this {@link RcsMessage} was successfully sent. - */ - public static final int SENT = 4; - - /** - * The status to indicate that this {@link RcsMessage} failed to send in an attempt before, and - * now being retried. - */ - public static final int RETRYING = 5; - - /** - * The status to indicate that this {@link RcsMessage} has permanently failed to send. - */ - public static final int FAILED = 6; - - /** - * The status to indicate that this {@link RcsMessage} was successfully received. - */ - public static final int RECEIVED = 7; - - /** - * The status to indicate that this {@link RcsMessage} was seen. - */ - public static final int SEEN = 9; - - /** - * @hide - */ - protected final RcsControllerCall mRcsControllerCall; - - /** - * @hide - */ - protected final int mId; - - @IntDef({ - DRAFT, QUEUED, SENDING, SENT, RETRYING, FAILED, RECEIVED, SEEN - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RcsMessageStatus { - } - - RcsMessage(RcsControllerCall rcsControllerCall, int id) { - mRcsControllerCall = rcsControllerCall; - mId = id; - } - - /** - * Returns the row Id from the common message. - * - * @hide - */ - public int getId() { - return mId; - } - - /** - * @return Returns the subscription ID that this {@link RcsMessage} was sent from, or delivered - * to. - * @throws RcsMessageStoreException if the value could not be read from the storage - * @see android.telephony.SubscriptionInfo#getSubscriptionId - */ - public int getSubscriptionId() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageSubId(mId, isIncoming(), callingPackage)); - } - - /** - * Sets the subscription ID that this {@link RcsMessage} was sent from, or delivered to and - * persists it into storage. - * - * @param subId The subscription ID to persists into storage. - * @throws RcsMessageStoreException if the value could not be persisted into storage - * @see android.telephony.SubscriptionInfo#getSubscriptionId - */ - @WorkerThread - public void setSubscriptionId(int subId) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setMessageSubId(mId, isIncoming(), subId, - callingPackage)); - } - - /** - * Sets the status of this message and persists it into storage. Please see - * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers. - * - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setStatus(@RcsMessageStatus int rcsMessageStatus) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setMessageStatus(mId, isIncoming(), rcsMessageStatus, - callingPackage)); - } - - /** - * @return Returns the status of this message. Please see - * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public @RcsMessageStatus int getStatus() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageStatus(mId, isIncoming(), callingPackage)); - } - - /** - * Sets the origination timestamp of this message and persists it into storage. Origination is - * defined as when the sender tapped the send button. - * - * @param timestamp The origination timestamp value in milliseconds passed after midnight, - * January 1, 1970 UTC - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setOriginationTimestamp(long timestamp) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setMessageOriginationTimestamp(mId, isIncoming(), - timestamp, callingPackage)); - } - - /** - * @return Returns the origination timestamp of this message in milliseconds passed after - * midnight, January 1, 1970 UTC. Origination is defined as when the sender tapped the send - * button. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getOriginationTimestamp() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageOriginationTimestamp(mId, isIncoming(), - callingPackage)); - } - - /** - * Sets the globally unique RCS message identifier for this message and persists it into - * storage. This function does not confirm that this message id is unique. Please see 4.4.5.2 - * - GSMA RCC.53 (RCS Device API 1.6 Specification - * - * @param rcsMessageGlobalId The globally RCS message identifier - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setRcsMessageId(String rcsMessageGlobalId) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setGlobalMessageIdForMessage(mId, isIncoming(), - rcsMessageGlobalId, callingPackage)); - } - - /** - * @return Returns the globally unique RCS message identifier for this message. Please see - * 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public String getRcsMessageId() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getGlobalMessageIdForMessage(mId, isIncoming(), - callingPackage)); - } - - /** - * @return Returns the user visible text included in this message. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public String getText() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getTextForMessage(mId, isIncoming(), - callingPackage)); - } - - /** - * Sets the user visible text for this message and persists in storage. - * - * @param text The text this message now has - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setText(String text) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setTextForMessage(mId, isIncoming(), text, - callingPackage)); - } - - /** - * @return Returns the associated latitude for this message, or - * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public double getLatitude() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getLatitudeForMessage(mId, isIncoming(), - callingPackage)); - } - - /** - * Sets the latitude for this message and persists in storage. - * - * @param latitude The latitude for this location message. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setLatitude(double latitude) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setLatitudeForMessage(mId, isIncoming(), latitude, - callingPackage)); - } - - /** - * @return Returns the associated longitude for this message, or - * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public double getLongitude() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getLongitudeForMessage(mId, isIncoming(), - callingPackage)); - } - - /** - * Sets the longitude for this message and persists in storage. - * - * @param longitude The longitude for this location message. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setLongitude(double longitude) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setLongitudeForMessage(mId, isIncoming(), longitude, - callingPackage)); - } - - /** - * Attaches an {@link RcsFileTransferPart} to this message and persists into storage. - * - * @param fileTransferCreationParameters The parameters to be used to create the - * {@link RcsFileTransferPart} - * @return A new instance of {@link RcsFileTransferPart} - * @throws RcsMessageStoreException if the file transfer could not be persisted into storage. - */ - @NonNull - @WorkerThread - public RcsFileTransferPart insertFileTransfer( - RcsFileTransferCreationParams fileTransferCreationParameters) - throws RcsMessageStoreException { - return new RcsFileTransferPart(mRcsControllerCall, mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.storeFileTransfer(mId, isIncoming(), - fileTransferCreationParameters, callingPackage))); - } - - /** - * @return Returns all the {@link RcsFileTransferPart}s associated with this message in an - * unmodifiable set. - * @throws RcsMessageStoreException if the file transfers could not be read from the storage - */ - @NonNull - @WorkerThread - public Set<RcsFileTransferPart> getFileTransferParts() throws RcsMessageStoreException { - Set<RcsFileTransferPart> fileTransferParts = new HashSet<>(); - - int[] fileTransferIds = mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getFileTransfersAttachedToMessage(mId, isIncoming(), - callingPackage)); - - for (int fileTransfer : fileTransferIds) { - fileTransferParts.add(new RcsFileTransferPart(mRcsControllerCall, fileTransfer)); - } - - return Collections.unmodifiableSet(fileTransferParts); - } - - /** - * Removes a {@link RcsFileTransferPart} from this message, and deletes it in storage. - * - * @param fileTransferPart The part to delete. - * @throws RcsMessageStoreException if the file transfer could not be removed from storage - */ - @WorkerThread - public void removeFileTransferPart(@NonNull RcsFileTransferPart fileTransferPart) - throws RcsMessageStoreException { - if (fileTransferPart == null) { - return; - } - - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.deleteFileTransfer(fileTransferPart.getId(), - callingPackage)); - } - - /** - * @return Returns {@code true} if this message was received on this device, {@code false} if it - * was sent. - */ - public abstract boolean isIncoming(); -} diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java deleted file mode 100644 index f0eea88ac8a9..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import static android.telephony.ims.RcsMessage.LOCATION_NOT_SET; - -import android.annotation.CheckResult; -import android.annotation.Nullable; -import android.os.Parcel; - -/** - * The collection of parameters to be passed into - * {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} and - * {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to create and persist - * {@link RcsMessage}s on an {@link RcsThread} - * - * @hide - */ -public class RcsMessageCreationParams { - // The globally unique id of the RcsMessage to be created. - private final String mRcsMessageGlobalId; - - // The subscription that this message was/will be received/sent from. - private final int mSubId; - // The sending/receiving status of the message - private final @RcsMessage.RcsMessageStatus int mMessageStatus; - // The timestamp of message creation - private final long mOriginationTimestamp; - // The user visible content of the message - private final String mText; - // The latitude of the message if this is a location message - private final double mLatitude; - // The longitude of the message if this is a location message - private final double mLongitude; - - /** - * @return Returns the globally unique RCS Message ID for the {@link RcsMessage} to be created. - * Please see 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification - */ - @Nullable - public String getRcsMessageGlobalId() { - return mRcsMessageGlobalId; - } - - /** - * @return Returns the subscription ID that was used to send or receive the {@link RcsMessage} - * to be created. - */ - public int getSubId() { - return mSubId; - } - - /** - * @return Returns the status for the {@link RcsMessage} to be created. - * @see RcsMessage.RcsMessageStatus - */ - public int getMessageStatus() { - return mMessageStatus; - } - - /** - * @return Returns the origination timestamp of the {@link RcsMessage} to be created in - * milliseconds passed after midnight, January 1, 1970 UTC. Origination is defined as when - * the sender tapped the send button. - */ - public long getOriginationTimestamp() { - return mOriginationTimestamp; - } - - /** - * @return Returns the user visible text contained in the {@link RcsMessage} to be created - */ - @Nullable - public String getText() { - return mText; - } - - /** - * @return Returns the latitude of the {@link RcsMessage} to be created, or - * {@link RcsMessage#LOCATION_NOT_SET} if the message does not contain a location. - */ - public double getLatitude() { - return mLatitude; - } - - /** - * @return Returns the longitude of the {@link RcsMessage} to be created, or - * {@link RcsMessage#LOCATION_NOT_SET} if the message does not contain a location. - */ - public double getLongitude() { - return mLongitude; - } - - /** - * The base builder for creating {@link RcsMessage}s on {@link RcsThread}s. - * - * @see RcsIncomingMessageCreationParams - */ - public static class Builder { - private String mRcsMessageGlobalId; - private int mSubId; - private @RcsMessage.RcsMessageStatus int mMessageStatus; - private long mOriginationTimestamp; - private String mText; - private double mLatitude = LOCATION_NOT_SET; - private double mLongitude = LOCATION_NOT_SET; - - /** - * @hide - */ - public Builder(long originationTimestamp, int subscriptionId) { - mOriginationTimestamp = originationTimestamp; - mSubId = subscriptionId; - } - - /** - * Sets the status of the {@link RcsMessage} to be built. - * - * @param rcsMessageStatus The status to be set - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#setStatus(int) - */ - @CheckResult - public Builder setStatus(@RcsMessage.RcsMessageStatus int rcsMessageStatus) { - mMessageStatus = rcsMessageStatus; - return this; - } - - /** - * Sets the globally unique RCS message identifier for the {@link RcsMessage} to be built. - * This function does not confirm that this message id is unique. Please see 4.4.5.2 - GSMA - * RCC.53 (RCS Device API 1.6 Specification) - * - * @param rcsMessageId The ID to be set - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#setRcsMessageId(String) - */ - @CheckResult - public Builder setRcsMessageId(String rcsMessageId) { - mRcsMessageGlobalId = rcsMessageId; - return this; - } - - /** - * Sets the text of the {@link RcsMessage} to be built. - * - * @param text The user visible text of the message - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#setText(String) - */ - @CheckResult - public Builder setText(String text) { - mText = text; - return this; - } - - /** - * Sets the latitude of the {@link RcsMessage} to be built. Please see US5-24 - GSMA RCC.71 - * (RCS Universal Profile Service Definition Document) - * - * @param latitude The latitude of the location information associated with this message. - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#setLatitude(double) - */ - @CheckResult - public Builder setLatitude(double latitude) { - mLatitude = latitude; - return this; - } - - /** - * Sets the longitude of the {@link RcsMessage} to be built. Please see US5-24 - GSMA RCC.71 - * (RCS Universal Profile Service Definition Document) - * - * @param longitude The longitude of the location information associated with this message. - * @return The same instance of {@link Builder} to chain methods - * @see RcsMessage#setLongitude(double) - */ - @CheckResult - public Builder setLongitude(double longitude) { - mLongitude = longitude; - return this; - } - - /** - * @return Builds and returns a newly created {@link RcsMessageCreationParams} - */ - public RcsMessageCreationParams build() { - return new RcsMessageCreationParams(this); - } - } - - protected RcsMessageCreationParams(Builder builder) { - mRcsMessageGlobalId = builder.mRcsMessageGlobalId; - mSubId = builder.mSubId; - mMessageStatus = builder.mMessageStatus; - mOriginationTimestamp = builder.mOriginationTimestamp; - mText = builder.mText; - mLatitude = builder.mLatitude; - mLongitude = builder.mLongitude; - } - - /** - * @hide - */ - RcsMessageCreationParams(Parcel in) { - mRcsMessageGlobalId = in.readString(); - mSubId = in.readInt(); - mMessageStatus = in.readInt(); - mOriginationTimestamp = in.readLong(); - mText = in.readString(); - mLatitude = in.readDouble(); - mLongitude = in.readDouble(); - } - - /** - * @hide - */ - public void writeToParcel(Parcel dest) { - dest.writeString(mRcsMessageGlobalId); - dest.writeInt(mSubId); - dest.writeInt(mMessageStatus); - dest.writeLong(mOriginationTimestamp); - dest.writeString(mText); - dest.writeDouble(mLatitude); - dest.writeDouble(mLongitude); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessageManager.java b/telephony/java/android/telephony/ims/RcsMessageManager.java deleted file mode 100644 index a1c7c0fefab2..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageManager.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemService; -import android.annotation.WorkerThread; -import android.content.Context; -import android.net.Uri; - -import java.util.List; - -/** - * RcsMessageManager is the application interface to RcsProvider and provides access methods to - * RCS related database tables. - * - * @hide - */ -@SystemService(Context.TELEPHONY_RCS_MESSAGE_SERVICE) -public class RcsMessageManager { - RcsControllerCall mRcsControllerCall; - - /** - * Use {@link Context#getSystemService(String)} to get an instance of this service. - * @hide - */ - public RcsMessageManager(Context context) { - mRcsControllerCall = new RcsControllerCall(context); - } - - /** - * Returns the first chunk of existing {@link RcsThread}s in the common storage. - * - * @param queryParameters Parameters to specify to return a subset of all RcsThreads. - * Passing a value of null will return all threads. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParams queryParameters) - throws RcsMessageStoreException { - return new RcsThreadQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getRcsThreads(queryParameters, - callingPackage))); - } - - /** - * Returns the next chunk of {@link RcsThread}s in the common storage. - * - * @param continuationToken A token to continue the query to get the next chunk. This is - * obtained through {@link RcsThreadQueryResult#getContinuationToken}. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsThreadQueryResult getRcsThreads(@NonNull RcsQueryContinuationToken continuationToken) - throws RcsMessageStoreException { - return new RcsThreadQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getRcsThreadsWithToken(continuationToken, - callingPackage))); - } - - /** - * Returns the first chunk of existing {@link RcsParticipant}s in the common storage. - * - * @param queryParameters Parameters to specify to return a subset of all RcsParticipants. - * Passing a value of null will return all participants. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsParticipantQueryResult getRcsParticipants( - @Nullable RcsParticipantQueryParams queryParameters) - throws RcsMessageStoreException { - return new RcsParticipantQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getParticipants(queryParameters, - callingPackage))); - } - - /** - * Returns the next chunk of {@link RcsParticipant}s in the common storage. - * - * @param continuationToken A token to continue the query to get the next chunk. This is - * obtained through - * {@link RcsParticipantQueryResult#getContinuationToken} - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsParticipantQueryResult getRcsParticipants( - @NonNull RcsQueryContinuationToken continuationToken) - throws RcsMessageStoreException { - return new RcsParticipantQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getParticipantsWithToken(continuationToken, - callingPackage))); - } - - /** - * Returns the first chunk of existing {@link RcsMessage}s in the common storage. - * - * @param queryParams Parameters to specify to return a subset of all RcsMessages. - * Passing a value of null will return all messages. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsMessageQueryResult getRcsMessages( - @Nullable RcsMessageQueryParams queryParams) throws RcsMessageStoreException { - return new RcsMessageQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessages(queryParams, callingPackage))); - } - - /** - * Returns the next chunk of {@link RcsMessage}s in the common storage. - * - * @param continuationToken A token to continue the query to get the next chunk. This is - * obtained through {@link RcsMessageQueryResult#getContinuationToken} - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsMessageQueryResult getRcsMessages( - @NonNull RcsQueryContinuationToken continuationToken) throws RcsMessageStoreException { - return new RcsMessageQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessagesWithToken(continuationToken, - callingPackage))); - } - - /** - * Returns the first chunk of existing {@link RcsEvent}s in the common storage. - * - * @param queryParams Parameters to specify to return a subset of all RcsEvents. - * Passing a value of null will return all events. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsEventQueryResult getRcsEvents( - @Nullable RcsEventQueryParams queryParams) throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getEvents(queryParams, callingPackage)) - .getRcsEventQueryResult(mRcsControllerCall); - } - - /** - * Returns the next chunk of {@link RcsEvent}s in the common storage. - * - * @param continuationToken A token to continue the query to get the next chunk. This is - * obtained through {@link RcsEventQueryResult#getContinuationToken}. - * @throws RcsMessageStoreException if the query could not be completed on the storage - */ - @WorkerThread - @NonNull - public RcsEventQueryResult getRcsEvents( - @NonNull RcsQueryContinuationToken continuationToken) throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getEventsWithToken(continuationToken, - callingPackage)) - .getRcsEventQueryResult(mRcsControllerCall); - } - - /** - * Persists an {@link RcsEvent} to common storage. - * - * @param rcsEvent The {@link RcsEvent} to persist into storage. - * @throws RcsMessageStoreException if the query could not be completed on the storage - * @see RcsGroupThreadNameChangedEvent - * @see RcsGroupThreadIconChangedEvent - * @see RcsGroupThreadParticipantJoinedEvent - * @see RcsGroupThreadParticipantLeftEvent - * @see RcsParticipantAliasChangedEvent - */ - @WorkerThread - @NonNull - public void persistRcsEvent(RcsEvent rcsEvent) throws RcsMessageStoreException { - rcsEvent.persist(mRcsControllerCall); - } - - /** - * Creates a new 1 to 1 thread with the given participant and persists it in the storage. - * - * @param recipient The {@link RcsParticipant} that will receive the messages in this thread. - * @return The newly created {@link Rcs1To1Thread} - * @throws RcsMessageStoreException if the thread could not be persisted in the storage - */ - @WorkerThread - @NonNull - public Rcs1To1Thread createRcs1To1Thread(@NonNull RcsParticipant recipient) - throws RcsMessageStoreException { - return new Rcs1To1Thread( - mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.createRcs1To1Thread(recipient.getId(), - callingPackage))); - } - - /** - * Creates a new group thread with the given participants and persists it in the storage. - * - * @throws RcsMessageStoreException if the thread could not be persisted in the storage - */ - @WorkerThread - @NonNull - public RcsGroupThread createGroupThread(@Nullable List<RcsParticipant> recipients, - @Nullable String groupName, @Nullable Uri groupIcon) throws RcsMessageStoreException { - int[] recipientIds = null; - if (recipients != null) { - recipientIds = new int[recipients.size()]; - - for (int i = 0; i < recipients.size(); i++) { - recipientIds[i] = recipients.get(i).getId(); - } - } - - int[] finalRecipientIds = recipientIds; - - int threadId = mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.createGroupThread(finalRecipientIds, groupName, - groupIcon, callingPackage)); - - return new RcsGroupThread(mRcsControllerCall, threadId); - } - - /** - * Delete the given {@link RcsThread} from the storage. - * - * @param thread The thread to be deleted. - * @throws RcsMessageStoreException if the thread could not be deleted from the storage - */ - @WorkerThread - public void deleteThread(@NonNull RcsThread thread) throws RcsMessageStoreException { - if (thread == null) { - return; - } - - boolean isDeleteSucceeded = mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.deleteThread(thread.getThreadId(), - thread.getThreadType(), callingPackage)); - - if (!isDeleteSucceeded) { - throw new RcsMessageStoreException("Could not delete RcsThread"); - } - } - - /** - * Creates a new participant and persists it in the storage. - * - * @param canonicalAddress The defining address (e.g. phone number) of the participant. - * @param alias The RCS alias for the participant. - * @throws RcsMessageStoreException if the participant could not be created on the storage - */ - @WorkerThread - @NonNull - public RcsParticipant createRcsParticipant(String canonicalAddress, @Nullable String alias) - throws RcsMessageStoreException { - return new RcsParticipant(mRcsControllerCall, mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.createRcsParticipant(canonicalAddress, alias, - callingPackage))); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl b/telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl deleted file mode 100644 index e9cbd9cc4ebe..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsMessageQueryParams; diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java deleted file mode 100644 index 9f9eafbd179b..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.InvalidParameterException; - -/** - * The parameters to pass into - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} in order to select a - * subset of {@link RcsMessage}s present in the message store. - * - * @hide - */ -public final class RcsMessageQueryParams implements Parcelable { - /** - * @hide - not meant for public use - */ - public static final int THREAD_ID_NOT_SET = -1; - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should - * be sorted in the same order of {@link RcsMessage}s that got persisted into storage for faster - * results. - */ - public static final int SORT_BY_CREATION_ORDER = 0; - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should - * be sorted according to the timestamp of {@link RcsMessage#getOriginationTimestamp()} - */ - public static final int SORT_BY_TIMESTAMP = 1; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP}) - public @interface SortingProperty { - } - - /** - * Bitmask flag to be used with {@link Builder#setMessageType(int)} to make - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return - * {@link RcsIncomingMessage}s. - */ - public static final int MESSAGE_TYPE_INCOMING = 0x0001; - - /** - * Bitmask flag to be used with {@link Builder#setMessageType(int)} to make - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return - * {@link RcsOutgoingMessage}s. - */ - public static final int MESSAGE_TYPE_OUTGOING = 0x0002; - - /** - * Bitmask flag to be used with {@link Builder#setFileTransferPresence(int)} to make - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return {@link RcsMessage}s - * that have an {@link RcsFileTransferPart} attached. - */ - public static final int MESSAGES_WITH_FILE_TRANSFERS = 0x0004; - - /** - * Bitmask flag to be used with {@link Builder#setFileTransferPresence(int)} to make - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return {@link RcsMessage}s - * that don't have an {@link RcsFileTransferPart} attached. - */ - public static final int MESSAGES_WITHOUT_FILE_TRANSFERS = 0x0008; - - /** - * @hide - not meant for public use - */ - public static final String MESSAGE_QUERY_PARAMETERS_KEY = "message_query_parameters"; - - // Whether the result should be filtered against incoming or outgoing messages - private int mMessageType; - // Whether the result should have file transfer messages attached or not - private int mFileTransferPresence; - // The SQL "Like" clause to filter messages - private String mMessageLike; - // The property the messages should be sorted against - private @SortingProperty int mSortingProperty; - // Whether the messages should be sorted in ascending order - private boolean mIsAscending; - // The number of results that should be returned with this query - private int mLimit; - // The thread that the results should be limited to - private int mThreadId; - - RcsMessageQueryParams(int messageType, int fileTransferPresence, String messageLike, - int threadId, @SortingProperty int sortingProperty, boolean isAscending, int limit) { - mMessageType = messageType; - mFileTransferPresence = fileTransferPresence; - mMessageLike = messageLike; - mSortingProperty = sortingProperty; - mIsAscending = isAscending; - mLimit = limit; - mThreadId = threadId; - } - - /** - * @return Returns the type of {@link RcsMessage}s that this {@link RcsMessageQueryParams} - * is set to query for. - */ - public int getMessageType() { - return mMessageType; - } - - /** - * @return Returns whether the result query should return {@link RcsMessage}s with - * {@link RcsFileTransferPart}s or not - */ - public int getFileTransferPresence() { - return mFileTransferPresence; - } - - /** - * @return Returns the SQL-inspired "LIKE" clause that will be used to match {@link RcsMessage}s - */ - public String getMessageLike() { - return mMessageLike; - } - - /** - * @return Returns the number of {@link RcsThread}s to be returned from the query. A value of - * 0 means there is no set limit. - */ - public int getLimit() { - return mLimit; - } - - /** - * @return Returns the property that will be used to sort the result against. - * @see SortingProperty - */ - public @SortingProperty int getSortingProperty() { - return mSortingProperty; - } - - /** - * @return Returns {@code true} if the result set will be sorted in ascending order, - * {@code false} if it will be sorted in descending order. - */ - public boolean getSortDirection() { - return mIsAscending; - } - - /** - * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get - * the thread that the result query should be limited to. - * - * As we do not expose any sort of integer ID's to public usage, this should be hidden. - * - * @hide - not meant for public use - */ - public int getThreadId() { - return mThreadId; - } - - /** - * A helper class to build the {@link RcsMessageQueryParams}. - */ - public static class Builder { - private @SortingProperty int mSortingProperty; - private int mMessageType; - private int mFileTransferPresence; - private String mMessageLike; - private boolean mIsAscending; - private int mLimit = 100; - private int mThreadId = THREAD_ID_NOT_SET; - - /** - * Creates a new builder for {@link RcsMessageQueryParams} to be used in - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} - * - */ - public Builder() { - // empty implementation - } - - /** - * Desired number of threads to be returned from the query. Passing in 0 will return all - * existing threads at once. The limit defaults to 100. - * - * @param limit The number to limit the query result to. - * @return The same instance of the builder to chain parameters. - * @throws InvalidParameterException If the given limit is negative. - */ - @CheckResult - public Builder setResultLimit(@IntRange(from = 0) int limit) - throws InvalidParameterException { - if (limit < 0) { - throw new InvalidParameterException("The query limit must be non-negative"); - } - - mLimit = limit; - return this; - } - - /** - * Sets the type of messages to be returned from the query. - * - * @param messageType The type of message to be returned. - * @return The same instance of the builder to chain parameters. - * @see RcsMessageQueryParams#MESSAGE_TYPE_INCOMING - * @see RcsMessageQueryParams#MESSAGE_TYPE_OUTGOING - */ - @CheckResult - public Builder setMessageType(int messageType) { - mMessageType = messageType; - return this; - } - - /** - * Sets whether file transfer messages should be included in the query result or not. - * - * @param fileTransferPresence Whether file transfers should be included in the result - * @return The same instance of the builder to chain parameters. - * @see RcsMessageQueryParams#MESSAGES_WITH_FILE_TRANSFERS - * @see RcsMessageQueryParams#MESSAGES_WITHOUT_FILE_TRANSFERS - */ - @CheckResult - public Builder setFileTransferPresence(int fileTransferPresence) { - mFileTransferPresence = fileTransferPresence; - return this; - } - - /** - * Sets an SQL-inspired "like" clause to match with messages. Using a percent sign ('%') - * wildcard matches any sequence of zero or more characters. Using an underscore ('_') - * wildcard matches any single character. Not using any wildcards would only perform a - * string match. The input string is case-insensitive. - * - * The input "Wh%" would match messages "who", "where" and "what", while the input "Wh_" - * would only match "who" - * - * @param messageLike The "like" clause for matching {@link RcsMessage}s. - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setMessageLike(String messageLike) { - mMessageLike = messageLike; - return this; - } - - /** - * Sets the property where the results should be sorted against. Defaults to - * {@link RcsMessageQueryParams.SortingProperty#SORT_BY_CREATION_ORDER} - * - * @param sortingProperty against which property the results should be sorted - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortProperty(@SortingProperty int sortingProperty) { - mSortingProperty = sortingProperty; - return this; - } - - /** - * Sets whether the results should be sorted ascending or descending - * - * @param isAscending whether the results should be sorted ascending - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortDirection(boolean isAscending) { - mIsAscending = isAscending; - return this; - } - - /** - * Limits the results to the given thread. - * - * @param thread the {@link RcsThread} that results should be limited to. If set to - * {@code null}, messages on all threads will be queried - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setThread(@Nullable RcsThread thread) { - if (thread == null) { - mThreadId = THREAD_ID_NOT_SET; - } else { - mThreadId = thread.getThreadId(); - } - return this; - } - - /** - * Builds the {@link RcsMessageQueryParams} to use in - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} - * - * @return An instance of {@link RcsMessageQueryParams} to use with the message - * query. - */ - public RcsMessageQueryParams build() { - return new RcsMessageQueryParams(mMessageType, mFileTransferPresence, mMessageLike, - mThreadId, mSortingProperty, mIsAscending, mLimit); - } - } - - /** - * Parcelable boilerplate below. - */ - private RcsMessageQueryParams(Parcel in) { - mMessageType = in.readInt(); - mFileTransferPresence = in.readInt(); - mMessageLike = in.readString(); - mSortingProperty = in.readInt(); - mIsAscending = in.readBoolean(); - mLimit = in.readInt(); - mThreadId = in.readInt(); - } - - public static final @android.annotation.NonNull Creator<RcsMessageQueryParams> CREATOR = - new Creator<RcsMessageQueryParams>() { - @Override - public RcsMessageQueryParams createFromParcel(Parcel in) { - return new RcsMessageQueryParams(in); - } - - @Override - public RcsMessageQueryParams[] newArray(int size) { - return new RcsMessageQueryParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mMessageType); - dest.writeInt(mFileTransferPresence); - dest.writeString(mMessageLike); - dest.writeInt(mSortingProperty); - dest.writeBoolean(mIsAscending); - dest.writeInt(mLimit); - dest.writeInt(mThreadId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java deleted file mode 100644 index 36bb78a0594b..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_INCOMING; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * The result of a {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} - * call. This class allows getting the token for querying the next batch of messages in order to - * prevent handling large amounts of data at once. - * - * @hide - */ -public final class RcsMessageQueryResult { - private final RcsControllerCall mRcsControllerCall; - private final RcsMessageQueryResultParcelable mRcsMessageQueryResultParcelable; - - RcsMessageQueryResult(RcsControllerCall rcsControllerCall, - RcsMessageQueryResultParcelable rcsMessageQueryResultParcelable) { - mRcsControllerCall = rcsControllerCall; - mRcsMessageQueryResultParcelable = rcsMessageQueryResultParcelable; - } - - /** - * Returns a token to call - * {@link RcsMessageStore#getRcsMessages(RcsQueryContinuationToken)} - * to get the next batch of {@link RcsMessage}s. - */ - @Nullable - public RcsQueryContinuationToken getContinuationToken() { - return mRcsMessageQueryResultParcelable.mContinuationToken; - } - - /** - * Returns all the {@link RcsMessage}s in the current query result. Call {@link - * RcsMessageStore#getRcsMessages(RcsQueryContinuationToken)} to get the next batch - * of {@link RcsMessage}s. - */ - @NonNull - public List<RcsMessage> getMessages() { - return mRcsMessageQueryResultParcelable.mMessageTypeIdPairs.stream() - .map(typeIdPair -> typeIdPair.getType() == MESSAGE_TYPE_INCOMING - ? new RcsIncomingMessage(mRcsControllerCall, typeIdPair.getId()) - : new RcsOutgoingMessage(mRcsControllerCall, typeIdPair.getId())) - .collect(Collectors.toList()); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.aidl b/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.aidl deleted file mode 100644 index 86928bfa41b8..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsMessageQueryResultParcelable; diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.java b/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.java deleted file mode 100644 index 4972f9bc4956..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageQueryResultParcelable.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.ims.RcsTypeIdPair; - -import java.util.ArrayList; -import java.util.List; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsMessageQueryResultParcelable implements Parcelable { - // The token to continue the query to get the next batch of results - final RcsQueryContinuationToken mContinuationToken; - // The message type and message ID pairs for all the messages in this query result - final List<RcsTypeIdPair> mMessageTypeIdPairs; - - public RcsMessageQueryResultParcelable( - RcsQueryContinuationToken continuationToken, - List<RcsTypeIdPair> messageTypeIdPairs) { - mContinuationToken = continuationToken; - mMessageTypeIdPairs = messageTypeIdPairs; - } - - private RcsMessageQueryResultParcelable(Parcel in) { - mContinuationToken = in.readParcelable( - RcsQueryContinuationToken.class.getClassLoader()); - - mMessageTypeIdPairs = new ArrayList<>(); - in.readTypedList(mMessageTypeIdPairs, RcsTypeIdPair.CREATOR); - } - - public static final Creator<RcsMessageQueryResultParcelable> CREATOR = - new Creator<RcsMessageQueryResultParcelable>() { - @Override - public RcsMessageQueryResultParcelable createFromParcel(Parcel in) { - return new RcsMessageQueryResultParcelable(in); - } - - @Override - public RcsMessageQueryResultParcelable[] newArray(int size) { - return new RcsMessageQueryResultParcelable[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mContinuationToken, flags); - dest.writeTypedList(mMessageTypeIdPairs); - } -} diff --git a/telephony/java/android/telephony/ims/RcsMessageSnippet.java b/telephony/java/android/telephony/ims/RcsMessageSnippet.java deleted file mode 100644 index 810316040470..000000000000 --- a/telephony/java/android/telephony/ims/RcsMessageSnippet.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.telephony.ims.RcsMessage.RcsMessageStatus; - -/** - * An immutable summary of the latest {@link RcsMessage} on an {@link RcsThread} - * - * @hide - */ -public final class RcsMessageSnippet implements Parcelable { - private final String mText; - private final @RcsMessageStatus int mStatus; - private final long mTimestamp; - - /** - * @hide - */ - public RcsMessageSnippet(String text, @RcsMessageStatus int status, long timestamp) { - mText = text; - mStatus = status; - mTimestamp = timestamp; - } - - /** - * @return Returns the text of the {@link RcsMessage} with highest origination timestamp value - * (i.e. latest) in this thread - */ - @Nullable - public String getSnippetText() { - return mText; - } - - /** - * @return Returns the status of the {@link RcsMessage} with highest origination timestamp value - * (i.e. latest) in this thread - */ - public @RcsMessageStatus int getSnippetStatus() { - return mStatus; - } - - /** - * @return Returns the timestamp of the {@link RcsMessage} with highest origination timestamp - * value (i.e. latest) in this thread - */ - public long getSnippetTimestamp() { - return mTimestamp; - } - - private RcsMessageSnippet(Parcel in) { - mText = in.readString(); - mStatus = in.readInt(); - mTimestamp = in.readLong(); - } - - public static final @android.annotation.NonNull Creator<RcsMessageSnippet> CREATOR = - new Creator<RcsMessageSnippet>() { - @Override - public RcsMessageSnippet createFromParcel(Parcel in) { - return new RcsMessageSnippet(in); - } - - @Override - public RcsMessageSnippet[] newArray(int size) { - return new RcsMessageSnippet[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mText); - dest.writeInt(mStatus); - dest.writeLong(mTimestamp); - } -} diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java deleted file mode 100644 index 7080ec6c5281..000000000000 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.WorkerThread; - -import java.util.ArrayList; -import java.util.List; - -/** - * This is a single instance of a message sent over RCS. - * - * @hide - */ -public class RcsOutgoingMessage extends RcsMessage { - RcsOutgoingMessage(RcsControllerCall rcsControllerCall, int id) { - super(rcsControllerCall, id); - } - - /** - * @return Returns the {@link RcsOutgoingMessageDelivery}s associated with this message. Please - * note that the deliveries returned for the {@link RcsOutgoingMessage} may not always match the - * {@link RcsParticipant}s on the {@link RcsGroupThread} as the group recipients may have - * changed. - * @throws RcsMessageStoreException if the outgoing deliveries could not be read from storage. - */ - @NonNull - @WorkerThread - public List<RcsOutgoingMessageDelivery> getOutgoingDeliveries() - throws RcsMessageStoreException { - int[] deliveryParticipants; - List<RcsOutgoingMessageDelivery> messageDeliveries = new ArrayList<>(); - - deliveryParticipants = mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageRecipients(mId, callingPackage)); - - if (deliveryParticipants != null) { - for (Integer deliveryParticipant : deliveryParticipants) { - messageDeliveries.add(new RcsOutgoingMessageDelivery( - mRcsControllerCall, deliveryParticipant, mId)); - } - } - - return messageDeliveries; - } - - /** - * @return Returns {@code false} as this is not an incoming message. - */ - @Override - public boolean isIncoming() { - return false; - } -} diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl deleted file mode 100644 index 0c38d9f5766b..000000000000 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsOutgoingMessageCreationParams; diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java deleted file mode 100644 index c001ffb354b0..000000000000 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * {@link RcsOutgoingMessageCreationParams} is a collection of parameters that should be passed - * into {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to generate an - * {@link RcsOutgoingMessage} on that {@link RcsThread} - * - * @hide - */ -public final class RcsOutgoingMessageCreationParams extends RcsMessageCreationParams - implements Parcelable { - /** - * A builder to instantiate and persist an {@link RcsOutgoingMessage} - */ - public static class Builder extends RcsMessageCreationParams.Builder { - - /** - * Creates a new {@link Builder} to create an instance of - * {@link RcsOutgoingMessageCreationParams}. - * - * @param originationTimestamp The timestamp of {@link RcsMessage} creation. The origination - * timestamp value in milliseconds passed after midnight, - * January 1, 1970 UTC - * @param subscriptionId The subscription ID that was used to send or receive this - * {@link RcsMessage} - * @see android.telephony.SubscriptionInfo#getSubscriptionId() - */ - public Builder(long originationTimestamp, int subscriptionId) { - super(originationTimestamp, subscriptionId); - } - - /** - * Creates configuration parameters for a new message. - */ - public RcsOutgoingMessageCreationParams build() { - return new RcsOutgoingMessageCreationParams(this); - } - } - - private RcsOutgoingMessageCreationParams(Builder builder) { - super(builder); - } - - private RcsOutgoingMessageCreationParams(Parcel in) { - super(in); - } - - public static final @NonNull Creator<RcsOutgoingMessageCreationParams> CREATOR = - new Creator<RcsOutgoingMessageCreationParams>() { - @Override - public RcsOutgoingMessageCreationParams createFromParcel(Parcel in) { - return new RcsOutgoingMessageCreationParams(in); - } - - @Override - public RcsOutgoingMessageCreationParams[] newArray(int size) { - return new RcsOutgoingMessageCreationParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest); - } -} diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java deleted file mode 100644 index df4a3e45bc03..000000000000 --- a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.WorkerThread; - -/** - * This class holds the delivery information of an {@link RcsOutgoingMessage} for each - * {@link RcsParticipant} that the message was intended for. - * - * @hide - */ -public class RcsOutgoingMessageDelivery { - private final RcsControllerCall mRcsControllerCall; - // The participant that this delivery is intended for - private final int mRecipientId; - // The message this delivery is associated with - private final int mRcsOutgoingMessageId; - - /** - * Constructor to be used with RcsOutgoingMessage.getDelivery() - * - * @hide - */ - RcsOutgoingMessageDelivery( - RcsControllerCall rcsControllerCall, int recipientId, int messageId) { - mRcsControllerCall = rcsControllerCall; - mRecipientId = recipientId; - mRcsOutgoingMessageId = messageId; - } - - /** - * Sets the delivery time of this outgoing delivery and persists into storage. - * - * @param deliveredTimestamp The timestamp to set to delivery. It is defined as milliseconds - * passed after midnight, January 1, 1970 UTC - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setDeliveredTimestamp(long deliveredTimestamp) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setOutgoingDeliveryDeliveredTimestamp( - mRcsOutgoingMessageId, mRecipientId, deliveredTimestamp, callingPackage)); - } - - /** - * @return Returns the delivered timestamp of the associated message to the associated - * participant. Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC. - * Returns 0 if the {@link RcsOutgoingMessage} is not delivered yet. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getDeliveredTimestamp() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getOutgoingDeliveryDeliveredTimestamp( - mRcsOutgoingMessageId, mRecipientId, callingPackage)); - } - - /** - * Sets the seen time of this outgoing delivery and persists into storage. - * - * @param seenTimestamp The timestamp to set to delivery. It is defined as milliseconds - * passed after midnight, January 1, 1970 UTC - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setSeenTimestamp(long seenTimestamp) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setOutgoingDeliverySeenTimestamp( - mRcsOutgoingMessageId, mRecipientId, seenTimestamp, callingPackage)); - } - - /** - * @return Returns the seen timestamp of the associated message by the associated - * participant. Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC. - * Returns 0 if the {@link RcsOutgoingMessage} is not seen yet. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public long getSeenTimestamp() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getOutgoingDeliverySeenTimestamp( - mRcsOutgoingMessageId, mRecipientId, callingPackage)); - } - - /** - * Sets the status of this outgoing delivery and persists into storage. - * - * @param status The status of the associated {@link RcsMessage}s delivery to the associated - * {@link RcsParticipant} - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setStatus(@RcsMessage.RcsMessageStatus int status) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setOutgoingDeliveryStatus( - mRcsOutgoingMessageId, mRecipientId, status, callingPackage)); - } - - /** - * @return Returns the status of this outgoing delivery. - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @WorkerThread - public @RcsMessage.RcsMessageStatus int getStatus() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getOutgoingDeliveryStatus(mRcsOutgoingMessageId, - mRecipientId, callingPackage)); - } - - /** - * @return Returns the recipient associated with this delivery. - */ - @NonNull - public RcsParticipant getRecipient() { - return new RcsParticipant(mRcsControllerCall, mRecipientId); - } - - /** - * @return Returns the {@link RcsOutgoingMessage} associated with this delivery. - */ - @NonNull - public RcsOutgoingMessage getMessage() { - return new RcsOutgoingMessage(mRcsControllerCall, mRcsOutgoingMessageId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java deleted file mode 100644 index 8512e960bfe6..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipant.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.Nullable; -import android.annotation.WorkerThread; - -/** - * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s. - * - * @hide - */ -public class RcsParticipant { - private final RcsControllerCall mRcsControllerCall; - // The row ID of this participant in the database - private final int mId; - - /** - * Constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController} - * to create instances of participants. This is not meant to be part of the SDK. - * - * @hide - */ - public RcsParticipant(RcsControllerCall rcsControllerCall, int id) { - mRcsControllerCall = rcsControllerCall; - mId = id; - } - - /** - * @return Returns the canonical address (i.e. normalized phone number) for this - * {@link RcsParticipant} - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public String getCanonicalAddress() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getRcsParticipantCanonicalAddress(mId, - callingPackage)); - } - - /** - * @return Returns the alias for this {@link RcsParticipant}. Alias is usually the real name of - * the person themselves. Please see US5-15 - GSMA RCC.71 (RCS Universal Profile Service - * Definition Document) - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public String getAlias() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getRcsParticipantAlias(mId, callingPackage)); - } - - /** - * Sets the alias for this {@link RcsParticipant} and persists it in storage. Alias is usually - * the real name of the person themselves. Please see US5-15 - GSMA RCC.71 (RCS Universal - * Profile Service Definition Document) - * - * @param alias The alias to set to. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setAlias(String alias) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setRcsParticipantAlias(mId, alias, callingPackage)); - } - - /** - * @return Returns the contact ID for this {@link RcsParticipant}. Contact ID is a unique ID for - * an {@link RcsParticipant} that is RCS provisioned. Please see 4.4.5 - GSMA RCC.53 (RCS Device - * API 1.6 Specification) - * @throws RcsMessageStoreException if the value could not be read from the storage - */ - @Nullable - @WorkerThread - public String getContactId() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getRcsParticipantContactId(mId, callingPackage)); - } - - /** - * Sets the contact ID for this {@link RcsParticipant}. Contact ID is a unique ID for - * an {@link RcsParticipant} that is RCS provisioned. Please see 4.4.5 - GSMA RCC.53 (RCS Device - * API 1.6 Specification) - * - * @param contactId The contact ID to set to. - * @throws RcsMessageStoreException if the value could not be persisted into storage - */ - @WorkerThread - public void setContactId(String contactId) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.setRcsParticipantContactId(mId, contactId, - callingPackage)); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof RcsParticipant)) { - return false; - } - RcsParticipant other = (RcsParticipant) obj; - - return mId == other.mId; - } - - @Override - public int hashCode() { - return mId; - } - - /** - * Returns the row id of this participant. This is not meant to be part of the SDK - * - * @hide - */ - public int getId() { - return mId; - } -} diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java deleted file mode 100644 index 865bc05132a2..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -/** - * An event that indicates an {@link RcsParticipant}'s alias was changed. Please see US18-2 - GSMA - * RCC.71 (RCS Universal Profile Service Definition Document) - * - * @hide - */ -public final class RcsParticipantAliasChangedEvent extends RcsEvent { - // The participant that changed their alias - private final RcsParticipant mParticipant; - // The new alias of the above participant - private final String mNewAlias; - - /** - * Creates a new {@link RcsParticipantAliasChangedEvent}. This event is not persisted into - * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called. - * - * @param timestamp The timestamp of when this event happened, in milliseconds passed after - * midnight, January 1st, 1970 UTC - * @param participant The {@link RcsParticipant} that got their alias changed - * @param newAlias The new alias the {@link RcsParticipant} has. - * @see RcsMessageStore#persistRcsEvent(RcsEvent) - */ - public RcsParticipantAliasChangedEvent(long timestamp, @NonNull RcsParticipant participant, - @Nullable String newAlias) { - super(timestamp); - mParticipant = participant; - mNewAlias = newAlias; - } - - /** - * @return Returns the {@link RcsParticipant} whose alias was changed. - */ - @NonNull - public RcsParticipant getParticipant() { - return mParticipant; - } - - /** - * @return Returns the alias of the associated {@link RcsParticipant} after this event happened - */ - @Nullable - public String getNewAlias() { - return mNewAlias; - } - - /** - * Persists the event to the data store. - * - * @hide - not meant for public use. - */ - @Override - void persist(RcsControllerCall rcsControllerCall) throws RcsMessageStoreException { - rcsControllerCall.call((iRcs, callingPackage) -> iRcs.createParticipantAliasChangedEvent( - getTimestamp(), getParticipant().getId(), getNewAlias(), callingPackage)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl deleted file mode 100644 index 64fe3b891572..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsParticipantAliasChangedEventDescriptor; diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java deleted file mode 100644 index 43b918c3e0f4..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.telephony.ims; - -import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * @hide - used only for internal communication with the ircs service - */ -public class RcsParticipantAliasChangedEventDescriptor extends RcsEventDescriptor { - // The ID of the participant that changed their alias - protected int mParticipantId; - // The new alias of the above participant - protected String mNewAlias; - - public RcsParticipantAliasChangedEventDescriptor(long timestamp, int participantId, - @Nullable String newAlias) { - super(timestamp); - mParticipantId = participantId; - mNewAlias = newAlias; - } - - @Override - @VisibleForTesting(visibility = PROTECTED) - public RcsParticipantAliasChangedEvent createRcsEvent(RcsControllerCall rcsControllerCall) { - return new RcsParticipantAliasChangedEvent( - mTimestamp, new RcsParticipant(rcsControllerCall, mParticipantId), mNewAlias); - } - - public static final @NonNull Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR = - new Creator<RcsParticipantAliasChangedEventDescriptor>() { - @Override - public RcsParticipantAliasChangedEventDescriptor createFromParcel(Parcel in) { - return new RcsParticipantAliasChangedEventDescriptor(in); - } - - @Override - public RcsParticipantAliasChangedEventDescriptor[] newArray(int size) { - return new RcsParticipantAliasChangedEventDescriptor[size]; - } - }; - - protected RcsParticipantAliasChangedEventDescriptor(Parcel in) { - super(in); - mNewAlias = in.readString(); - mParticipantId = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeString(mNewAlias); - dest.writeInt(mParticipantId); - } -} diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl deleted file mode 100644 index b7c0f93c8c5f..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsParticipantQueryParams; diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java deleted file mode 100644 index 21107a2f54e5..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.InvalidParameterException; - -/** - * The parameters to pass into - * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} in order to select a - * subset of {@link RcsThread}s present in the message store. - * - * @hide - */ -public final class RcsParticipantQueryParams implements Parcelable { - /** - * Flag to set with {@link Builder#setSortProperty(int)} to sort the results in the order of - * creation time for faster query results - */ - public static final int SORT_BY_CREATION_ORDER = 0; - - /** - * Flag to set with {@link Builder#setSortProperty(int)} to sort depending on the - * {@link RcsParticipant} aliases - */ - public static final int SORT_BY_ALIAS = 1; - - /** - * Flag to set with {@link Builder#setSortProperty(int)} to sort depending on the - * {@link RcsParticipant} canonical addresses - */ - public static final int SORT_BY_CANONICAL_ADDRESS = 2; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_ALIAS, SORT_BY_CANONICAL_ADDRESS}) - public @interface SortingProperty { - } - - // The SQL "like" statement to filter against participant aliases - private String mAliasLike; - // The SQL "like" statement to filter against canonical addresses - private String mCanonicalAddressLike; - // The property to sort the result against - private @SortingProperty int mSortingProperty; - // Whether to sort the result in ascending order - private boolean mIsAscending; - // The number of results to be returned from the query - private int mLimit; - // Used to limit the results to participants of a single thread - private int mThreadId; - - /** - * @hide - */ - public static final String PARTICIPANT_QUERY_PARAMETERS_KEY = "participant_query_parameters"; - - RcsParticipantQueryParams(int rcsThreadId, String aliasLike, String canonicalAddressLike, - @SortingProperty int sortingProperty, boolean isAscending, - int limit) { - mThreadId = rcsThreadId; - mAliasLike = aliasLike; - mCanonicalAddressLike = canonicalAddressLike; - mSortingProperty = sortingProperty; - mIsAscending = isAscending; - mLimit = limit; - } - - /** - * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get - * the thread that the result query should be limited to. - * - * As we do not expose any sort of integer ID's to public usage, this should be hidden. - * - * @hide - not meant for public use - */ - public int getThreadId() { - return mThreadId; - } - - /** - * @return Returns the SQL-inspired "LIKE" clause that will be used to match - * {@link RcsParticipant}s with respect to their aliases - * - * @see RcsParticipant#getAlias() - */ - public String getAliasLike() { - return mAliasLike; - } - - /** - * @return Returns the SQL-inspired "LIKE" clause that will be used to match - * {@link RcsParticipant}s with respect to their canonical addresses. - * - * @see RcsParticipant#getCanonicalAddress() - */ - public String getCanonicalAddressLike() { - return mCanonicalAddressLike; - } - - /** - * @return Returns the number of {@link RcsParticipant}s to be returned from the query. A value - * of 0 means there is no set limit. - */ - public int getLimit() { - return mLimit; - } - - /** - * @return Returns the property that will be used to sort the result against. - * @see SortingProperty - */ - public int getSortingProperty() { - return mSortingProperty; - } - - /** - * @return Returns {@code true} if the result set will be sorted in ascending order, - * {@code false} if it will be sorted in descending order. - */ - public boolean getSortDirection() { - return mIsAscending; - } - - /** - * A helper class to build the {@link RcsParticipantQueryParams}. - */ - public static class Builder { - private String mAliasLike; - private String mCanonicalAddressLike; - private @SortingProperty int mSortingProperty; - private boolean mIsAscending; - private int mLimit = 100; - private int mThreadId; - - /** - * Creates a new builder for {@link RcsParticipantQueryParams} to be used in - * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} - */ - public Builder() { - // empty implementation - } - - /** - * Limits the resulting {@link RcsParticipant}s to only the given {@link RcsThread} - * - * @param rcsThread The thread that the participants should be searched in. - * @return The same {@link Builder} to chain methods. - */ - @CheckResult - public Builder setThread(RcsThread rcsThread) { - mThreadId = rcsThread.getThreadId(); - return this; - } - - /** - * Sets an SQL-inspired "like" clause to match with participant aliases. Using a percent - * sign ('%') wildcard matches any sequence of zero or more characters. Using an underscore - * ('_') wildcard matches any single character. Not using any wildcards would only perform a - * string match.The input string is case-insensitive. - * - * The input "An%e" would match {@link RcsParticipant}s with names Anne, Annie, Antonie, - * while the input "An_e" would only match Anne. - * - * @param likeClause The like clause to use for matching {@link RcsParticipant} aliases. - * @return The same {@link Builder} to chain methods - */ - @CheckResult - public Builder setAliasLike(String likeClause) { - mAliasLike = likeClause; - return this; - } - - /** - * Sets an SQL-inspired "like" clause to match with participant addresses. Using a percent - * sign ('%') wildcard matches any sequence of zero or more characters. Using an underscore - * ('_') wildcard matches any single character. Not using any wildcards would only perform a - * string match. The input string is case-insensitive. - * - * The input "+999%111" would match {@link RcsParticipant}s with addresses like "+9995111" - * or "+99955555111", while the input "+999_111" would only match "+9995111". - * - * @param likeClause The like clause to use for matching {@link RcsParticipant} canonical - * addresses. - * @return The same {@link Builder} to chain methods - */ - @CheckResult - public Builder setCanonicalAddressLike(String likeClause) { - mCanonicalAddressLike = likeClause; - return this; - } - - /** - * Desired number of threads to be returned from the query. Passing in 0 will return all - * existing threads at once. The limit defaults to 100. - * - * @param limit The number to limit the query result to. - * @return The same instance of the builder to chain parameters. - * @throws InvalidParameterException If the given limit is negative. - */ - @CheckResult - public Builder setResultLimit(@IntRange(from = 0) int limit) - throws InvalidParameterException { - if (limit < 0) { - throw new InvalidParameterException("The query limit must be non-negative"); - } - - mLimit = limit; - return this; - } - - /** - * Sets the property where the results should be sorted against. Defaults to - * {@link RcsParticipantQueryParams.SortingProperty#SORT_BY_CREATION_ORDER} - * - * @param sortingProperty against which property the results should be sorted - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortProperty(@SortingProperty int sortingProperty) { - mSortingProperty = sortingProperty; - return this; - } - - /** - * Sets whether the results should be sorted ascending or descending - * - * @param isAscending whether the results should be sorted ascending - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortDirection(boolean isAscending) { - mIsAscending = isAscending; - return this; - } - - /** - * Builds the {@link RcsParticipantQueryParams} to use in - * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} - * - * @return An instance of {@link RcsParticipantQueryParams} to use with the participant - * query. - */ - public RcsParticipantQueryParams build() { - return new RcsParticipantQueryParams(mThreadId, mAliasLike, mCanonicalAddressLike, - mSortingProperty, mIsAscending, mLimit); - } - } - - /** - * Parcelable boilerplate below. - */ - private RcsParticipantQueryParams(Parcel in) { - mAliasLike = in.readString(); - mCanonicalAddressLike = in.readString(); - mSortingProperty = in.readInt(); - mIsAscending = in.readByte() == 1; - mLimit = in.readInt(); - mThreadId = in.readInt(); - } - - public static final @android.annotation.NonNull Creator<RcsParticipantQueryParams> CREATOR = - new Creator<RcsParticipantQueryParams>() { - @Override - public RcsParticipantQueryParams createFromParcel(Parcel in) { - return new RcsParticipantQueryParams(in); - } - - @Override - public RcsParticipantQueryParams[] newArray(int size) { - return new RcsParticipantQueryParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mAliasLike); - dest.writeString(mCanonicalAddressLike); - dest.writeInt(mSortingProperty); - dest.writeByte((byte) (mIsAscending ? 1 : 0)); - dest.writeInt(mLimit); - dest.writeInt(mThreadId); - } - -} diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java deleted file mode 100644 index 0721dfdf5803..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * The result of a {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} - * call. This class allows getting the token for querying the next batch of participants in order to - * prevent handling large amounts of data at once. - * - * @hide - */ -public final class RcsParticipantQueryResult { - private final RcsControllerCall mRcsControllerCall; - private final RcsParticipantQueryResultParcelable mRcsParticipantQueryResultParcelable; - - RcsParticipantQueryResult( - RcsControllerCall rcsControllerCall, - RcsParticipantQueryResultParcelable rcsParticipantQueryResultParcelable) { - mRcsControllerCall = rcsControllerCall; - mRcsParticipantQueryResultParcelable = rcsParticipantQueryResultParcelable; - } - - /** - * Returns a token to call - * {@link RcsMessageStore#getRcsParticipants(RcsQueryContinuationToken)} - * to get the next batch of {@link RcsParticipant}s. - */ - @Nullable - public RcsQueryContinuationToken getContinuationToken() { - return mRcsParticipantQueryResultParcelable.mContinuationToken; - } - - /** - * Returns all the {@link RcsParticipant}s in the current query result. Call {@link - * RcsMessageStore#getRcsParticipants(RcsQueryContinuationToken)} to get the next - * batch of {@link RcsParticipant}s. - */ - @NonNull - public List<RcsParticipant> getParticipants() { - return mRcsParticipantQueryResultParcelable.mParticipantIds.stream() - .map(participantId -> new RcsParticipant(mRcsControllerCall, participantId)) - .collect(Collectors.toList()); - } -} diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl deleted file mode 100644 index 54c72e70fac2..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsParticipantQueryResultParcelable; diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java deleted file mode 100644 index 239b0e9b0fc0..000000000000 --- a/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.List; - -/** - * @hide - */ -public final class RcsParticipantQueryResultParcelable implements Parcelable { - final RcsQueryContinuationToken mContinuationToken; - final List<Integer> mParticipantIds; - - public RcsParticipantQueryResultParcelable( - RcsQueryContinuationToken continuationToken, - List<Integer> participantIds) { - mContinuationToken = continuationToken; - mParticipantIds = participantIds; - } - - private RcsParticipantQueryResultParcelable(Parcel in) { - mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader()); - mParticipantIds = new ArrayList<>(); - in.readList(mParticipantIds, Integer.class.getClassLoader()); - } - - public static final Parcelable.Creator<RcsParticipantQueryResultParcelable> CREATOR = - new Parcelable.Creator<RcsParticipantQueryResultParcelable>() { - @Override - public RcsParticipantQueryResultParcelable createFromParcel(Parcel in) { - return new RcsParticipantQueryResultParcelable(in); - } - - @Override - public RcsParticipantQueryResultParcelable[] newArray(int size) { - return new RcsParticipantQueryResultParcelable[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mContinuationToken, flags); - dest.writeList(mParticipantIds); - } -} diff --git a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl deleted file mode 100644 index 319379a462de..000000000000 --- a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsQueryContinuationToken; diff --git a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java deleted file mode 100644 index 982263ac5c97..000000000000 --- a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.IntDef; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * A token for enabling continuation queries. Instances are acquired through - * {@code getContinuationToken} on result objects after initial query is done. - * - * @see RcsEventQueryResult#getContinuationToken() - * @see RcsMessageQueryResult#getContinuationToken() - * @see RcsParticipantQueryResult#getContinuationToken() - * @see RcsThreadQueryResult#getContinuationToken() - * - * @hide - */ -public final class RcsQueryContinuationToken implements Parcelable { - /** - * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing - * {@link RcsEvent} queries - */ - public static final int EVENT_QUERY_CONTINUATION_TOKEN_TYPE = 0; - - /** - * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing - * {@link RcsMessage} queries - */ - public static final int MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE = 1; - - /** - * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing - * {@link RcsParticipant} queries - */ - public static final int PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE = 2; - - /** - * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing - * {@link RcsThread} queries - */ - public static final int THREAD_QUERY_CONTINUATION_TOKEN_TYPE = 3; - - /** - * @hide - not meant for public use - */ - public static final String QUERY_CONTINUATION_TOKEN = "query_continuation_token"; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({EVENT_QUERY_CONTINUATION_TOKEN_TYPE, MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE, - PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE, THREAD_QUERY_CONTINUATION_TOKEN_TYPE}) - public @interface ContinuationTokenType {} - - // The type of query this token should allow to continue - private @ContinuationTokenType int mQueryType; - // The raw query string for the initial query - private final String mRawQuery; - // The number of results that is returned with each query - private final int mLimit; - // The offset value that this query should start the query from - private int mOffset; - - /** - * @hide - */ - public RcsQueryContinuationToken(@ContinuationTokenType int queryType, String rawQuery, - int limit, int offset) { - mQueryType = queryType; - mRawQuery = rawQuery; - mLimit = limit; - mOffset = offset; - } - - /** - * Returns the original raw query used on {@link com.android.providers.telephony.RcsProvider} - * @hide - */ - public String getRawQuery() { - return mRawQuery; - } - - /** - * Returns which index this continuation query should start from - * @hide - */ - public int getOffset() { - return mOffset; - } - - /** - * Increments the offset by the amount of result rows returned with the continuation query for - * the next query. - * @hide - */ - public void incrementOffset() { - mOffset += mLimit; - } - - /** - * Returns the type of query that this {@link RcsQueryContinuationToken} is intended to be used - * to continue. - */ - public @ContinuationTokenType int getQueryType() { - return mQueryType; - } - - private RcsQueryContinuationToken(Parcel in) { - mQueryType = in.readInt(); - mRawQuery = in.readString(); - mLimit = in.readInt(); - mOffset = in.readInt(); - } - - public static final @android.annotation.NonNull Creator<RcsQueryContinuationToken> CREATOR = - new Creator<RcsQueryContinuationToken>() { - @Override - public RcsQueryContinuationToken createFromParcel(Parcel in) { - return new RcsQueryContinuationToken(in); - } - - @Override - public RcsQueryContinuationToken[] newArray(int size) { - return new RcsQueryContinuationToken[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mQueryType); - dest.writeString(mRawQuery); - dest.writeInt(mLimit); - dest.writeInt(mOffset); - } -} diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java deleted file mode 100644 index efb2cca21c19..000000000000 --- a/telephony/java/android/telephony/ims/RcsThread.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1; -import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_GROUP; - -import android.annotation.NonNull; -import android.annotation.WorkerThread; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * RcsThread represents a single RCS conversation thread. It holds messages that were sent and - * received and events that occurred on that thread. - * - * @hide - */ -public abstract class RcsThread { - /** - * The rcs_participant_thread_id that represents this thread in the database - * - * @hide - */ - protected int mThreadId; - - /** - * @hide - */ - protected final RcsControllerCall mRcsControllerCall; - - /** - * @hide - */ - protected RcsThread(RcsControllerCall rcsControllerCall, int threadId) { - mThreadId = threadId; - mRcsControllerCall = rcsControllerCall; - } - - /** - * @return Returns the summary of the latest message in this {@link RcsThread} packaged in an - * {@link RcsMessageSnippet} object - */ - @WorkerThread - @NonNull - public RcsMessageSnippet getSnippet() throws RcsMessageStoreException { - return mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessageSnippet(mThreadId, callingPackage)); - } - - /** - * Adds a new {@link RcsIncomingMessage} to this RcsThread and persists it in storage. - * - * @throws RcsMessageStoreException if the message could not be persisted into storage. - */ - @WorkerThread - @NonNull - public RcsIncomingMessage addIncomingMessage( - @NonNull RcsIncomingMessageCreationParams rcsIncomingMessageCreationParams) - throws RcsMessageStoreException { - int messageId = mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.addIncomingMessage(mThreadId, - rcsIncomingMessageCreationParams, callingPackage)); - return new RcsIncomingMessage(mRcsControllerCall, messageId); - } - - /** - * Adds a new {@link RcsOutgoingMessage} to this RcsThread and persists it in storage. - * - * @throws RcsMessageStoreException if the message could not be persisted into storage. - */ - @WorkerThread - @NonNull - public RcsOutgoingMessage addOutgoingMessage( - @NonNull RcsOutgoingMessageCreationParams rcsOutgoingMessageCreationParams) - throws RcsMessageStoreException { - int messageId = mRcsControllerCall.call((iRcs, callingPackage) -> iRcs.addOutgoingMessage( - mThreadId, rcsOutgoingMessageCreationParams, callingPackage)); - - return new RcsOutgoingMessage(mRcsControllerCall, messageId); - } - - /** - * Deletes an {@link RcsMessage} from this RcsThread and updates the storage. - * - * @param rcsMessage The message to delete from the thread - * @throws RcsMessageStoreException if the message could not be deleted - */ - @WorkerThread - public void deleteMessage(@NonNull RcsMessage rcsMessage) throws RcsMessageStoreException { - mRcsControllerCall.callWithNoReturn( - (iRcs, callingPackage) -> iRcs.deleteMessage(rcsMessage.getId(), - rcsMessage.isIncoming(), mThreadId, - isGroup(), callingPackage)); - } - - /** - * Convenience function for loading all the {@link RcsMessage}s in this {@link RcsThread}. For - * a more detailed and paginated query, please use - * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} - * - * @return Loads the {@link RcsMessage}s in this thread and returns them in an immutable list. - * @throws RcsMessageStoreException if the messages could not be read from the storage - */ - @WorkerThread - @NonNull - public RcsMessageQueryResult getMessages() throws RcsMessageStoreException { - RcsMessageQueryParams queryParams = - new RcsMessageQueryParams.Builder().setThread(this).build(); - return new RcsMessageQueryResult(mRcsControllerCall, - mRcsControllerCall.call( - (iRcs, callingPackage) -> iRcs.getMessages(queryParams, callingPackage))); - } - - /** - * @return Returns whether this is a group thread or not - */ - public abstract boolean isGroup(); - - /** - * @hide - */ - @VisibleForTesting - public int getThreadId() { - return mThreadId; - } - - /** - * @hide - */ - public int getThreadType() { - return isGroup() ? THREAD_TYPE_GROUP : THREAD_TYPE_1_TO_1; - } -} diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl deleted file mode 100644 index 3f351dc5efee..000000000000 --- a/telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsThreadQueryParams; diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java deleted file mode 100644 index da7cdb016034..000000000000 --- a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.annotation.CheckResult; -import android.annotation.IntDef; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} in - * order to select a subset of {@link RcsThread}s present in the message store. - * - * @hide - */ -public final class RcsThreadQueryParams implements Parcelable { - /** - * Bitmask flag to be used with {@link Builder#setThreadType(int)} to make - * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} return - * {@link RcsGroupThread}s. - */ - public static final int THREAD_TYPE_GROUP = 0x0001; - - /** - * Bitmask flag to be used with {@link Builder#setThreadType(int)} to make - * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} return - * {@link Rcs1To1Thread}s. - */ - public static final int THREAD_TYPE_1_TO_1 = 0x0002; - - // The type of threads to be filtered with the query - private final int mThreadType; - // The list of participants that are expected in the resulting threads - private final List<Integer> mRcsParticipantIds; - // The number of RcsThread's that should be returned with this query - private final int mLimit; - // The property which the result of the query should be sorted against - private final @SortingProperty int mSortingProperty; - // Whether the sorting should be done in ascending - private final boolean mIsAscending; - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should - * be sorted in the order of {@link RcsThread} creation time for faster results. - */ - public static final int SORT_BY_CREATION_ORDER = 0; - - /** - * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should - * be sorted according to the timestamp of {@link RcsThread#getSnippet()} - */ - public static final int SORT_BY_TIMESTAMP = 1; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP}) - public @interface SortingProperty { - } - - /** - * @hide - */ - public static final String THREAD_QUERY_PARAMETERS_KEY = "thread_query_parameters"; - - RcsThreadQueryParams(int threadType, Set<RcsParticipant> participants, - int limit, int sortingProperty, boolean isAscending) { - mThreadType = threadType; - mRcsParticipantIds = convertParticipantSetToIdList(participants); - mLimit = limit; - mSortingProperty = sortingProperty; - mIsAscending = isAscending; - } - - private static List<Integer> convertParticipantSetToIdList(Set<RcsParticipant> participants) { - List<Integer> ids = new ArrayList<>(participants.size()); - for (RcsParticipant participant : participants) { - ids.add(participant.getId()); - } - return ids; - } - - /** - * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get - * the list of participant IDs. - * - * As we don't expose any integer ID's to API users, this should stay hidden - * - * @hide - not meant for public use - */ - public List<Integer> getRcsParticipantsIds() { - return Collections.unmodifiableList(mRcsParticipantIds); - } - - /** - * @return Returns the bitmask flag for types of {@link RcsThread}s that this query should - * return. - */ - public int getThreadType() { - return mThreadType; - } - - /** - * @return Returns the number of {@link RcsThread}s to be returned from the query. A value - * of 0 means there is no set limit. - */ - public int getLimit() { - return mLimit; - } - - /** - * @return Returns the property that will be used to sort the result against. - * @see SortingProperty - */ - public @SortingProperty int getSortingProperty() { - return mSortingProperty; - } - - /** - * @return Returns {@code true} if the result set will be sorted in ascending order, - * {@code false} if it will be sorted in descending order. - */ - public boolean getSortDirection() { - return mIsAscending; - } - - /** - * A helper class to build the {@link RcsThreadQueryParams}. - */ - public static class Builder { - private int mThreadType; - private Set<RcsParticipant> mParticipants; - private int mLimit = 100; - private @SortingProperty int mSortingProperty; - private boolean mIsAscending; - - /** - * Constructs a {@link RcsThreadQueryParams.Builder} to help build an - * {@link RcsThreadQueryParams} - */ - public Builder() { - mParticipants = new HashSet<>(); - } - - /** - * Limits the query to only return group threads. - * - * @param threadType Whether to limit the query result to group threads. - * @return The same instance of the builder to chain parameters. - * @see RcsThreadQueryParams#THREAD_TYPE_GROUP - * @see RcsThreadQueryParams#THREAD_TYPE_1_TO_1 - */ - @CheckResult - public Builder setThreadType(int threadType) { - mThreadType = threadType; - return this; - } - - /** - * Limits the query to only return threads that contain the given participant. If this - * property was not set, participants will not be taken into account while querying for - * threads. - * - * @param participant The participant that must be included in all of the returned threads. - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setParticipant(@NonNull RcsParticipant participant) { - mParticipants.add(participant); - return this; - } - - /** - * Limits the query to only return threads that contain the given list of participants. If - * this property was not set, participants will not be taken into account while querying - * for threads. - * - * @param participants An iterable list of participants that must be included in all of the - * returned threads. - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setParticipants(@NonNull List<RcsParticipant> participants) { - mParticipants.addAll(participants); - return this; - } - - /** - * Desired number of threads to be returned from the query. Passing in 0 will return all - * existing threads at once. The limit defaults to 100. - * - * @param limit The number to limit the query result to. - * @return The same instance of the builder to chain parameters. - * @throws InvalidParameterException If the given limit is negative. - */ - @CheckResult - public Builder setResultLimit(@IntRange(from = 0) int limit) - throws InvalidParameterException { - if (limit < 0) { - throw new InvalidParameterException("The query limit must be non-negative"); - } - - mLimit = limit; - return this; - } - - /** - * Sets the property where the results should be sorted against. Defaults to - * {@link SortingProperty#SORT_BY_CREATION_ORDER} - * - * @param sortingProperty whether to sort in ascending order or not - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortProperty(@SortingProperty int sortingProperty) { - mSortingProperty = sortingProperty; - return this; - } - - /** - * Sets whether the results should be sorted ascending or descending - * - * @param isAscending whether the results should be sorted ascending - * @return The same instance of the builder to chain parameters. - */ - @CheckResult - public Builder setSortDirection(boolean isAscending) { - mIsAscending = isAscending; - return this; - } - - /** - * Builds the {@link RcsThreadQueryParams} to use in - * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} - * - * @return An instance of {@link RcsThreadQueryParams} to use with the thread query. - */ - public RcsThreadQueryParams build() { - return new RcsThreadQueryParams(mThreadType, mParticipants, mLimit, - mSortingProperty, mIsAscending); - } - } - - /** - * Parcelable boilerplate below. - */ - private RcsThreadQueryParams(Parcel in) { - mThreadType = in.readInt(); - mRcsParticipantIds = new ArrayList<>(); - in.readList(mRcsParticipantIds, Integer.class.getClassLoader()); - mLimit = in.readInt(); - mSortingProperty = in.readInt(); - mIsAscending = in.readByte() == 1; - } - - public static final @android.annotation.NonNull Creator<RcsThreadQueryParams> CREATOR = - new Creator<RcsThreadQueryParams>() { - @Override - public RcsThreadQueryParams createFromParcel(Parcel in) { - return new RcsThreadQueryParams(in); - } - - @Override - public RcsThreadQueryParams[] newArray(int size) { - return new RcsThreadQueryParams[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mThreadType); - dest.writeList(mRcsParticipantIds); - dest.writeInt(mLimit); - dest.writeInt(mSortingProperty); - dest.writeByte((byte) (mIsAscending ? 1 : 0)); - } -} diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java deleted file mode 100644 index 3de25de19430..000000000000 --- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.util.List; -import java.util.stream.Collectors; - - -/** - * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} - * call. This class allows getting the token for querying the next batch of threads in order to - * prevent handling large amounts of data at once. - * - * @hide - */ -public final class RcsThreadQueryResult { - private final RcsControllerCall mRcsControllerCall; - private final RcsThreadQueryResultParcelable mRcsThreadQueryResultParcelable; - - RcsThreadQueryResult(RcsControllerCall rcsControllerCall, - RcsThreadQueryResultParcelable rcsThreadQueryResultParcelable) { - mRcsControllerCall = rcsControllerCall; - mRcsThreadQueryResultParcelable = rcsThreadQueryResultParcelable; - } - - /** - * Returns a token to call - * {@link RcsMessageStore#getRcsThreads(RcsQueryContinuationToken)} - * to get the next batch of {@link RcsThread}s. - */ - @Nullable - public RcsQueryContinuationToken getContinuationToken() { - return mRcsThreadQueryResultParcelable.mContinuationToken; - } - - /** - * Returns all the RcsThreads in the current query result. Call {@link - * RcsMessageStore#getRcsThreads(RcsQueryContinuationToken)} to get the next batch of - * {@link RcsThread}s. - */ - @NonNull - public List<RcsThread> getThreads() { - return mRcsThreadQueryResultParcelable.mRcsThreadIds.stream() - .map(typeIdPair -> typeIdPair.getType() == THREAD_TYPE_1_TO_1 - ? new Rcs1To1Thread(mRcsControllerCall, typeIdPair.getId()) - : new RcsGroupThread(mRcsControllerCall, typeIdPair.getId())) - .collect(Collectors.toList()); - } -} diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl deleted file mode 100644 index 05bd61de73e3..000000000000 --- a/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright 2019, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -parcelable RcsThreadQueryResultParcelable; diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java deleted file mode 100644 index 89dd1d48ef9b..000000000000 --- a/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims; - -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.ims.RcsTypeIdPair; - -import java.util.ArrayList; -import java.util.List; - -/** - * @hide - */ -public final class RcsThreadQueryResultParcelable implements Parcelable { - final RcsQueryContinuationToken mContinuationToken; - final List<RcsTypeIdPair> mRcsThreadIds; - - public RcsThreadQueryResultParcelable( - RcsQueryContinuationToken continuationToken, - List<RcsTypeIdPair> rcsThreadIds) { - mContinuationToken = continuationToken; - mRcsThreadIds = rcsThreadIds; - } - - private RcsThreadQueryResultParcelable(Parcel in) { - mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader()); - mRcsThreadIds = new ArrayList<>(); - in.readList(mRcsThreadIds, RcsTypeIdPair.class.getClassLoader()); - } - - public static final Parcelable.Creator<RcsThreadQueryResultParcelable> CREATOR = - new Parcelable.Creator<RcsThreadQueryResultParcelable>() { - @Override - public RcsThreadQueryResultParcelable createFromParcel(Parcel in) { - return new RcsThreadQueryResultParcelable(in); - } - - @Override - public RcsThreadQueryResultParcelable[] newArray(int size) { - return new RcsThreadQueryResultParcelable[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mContinuationToken, flags); - dest.writeList(mRcsThreadIds); - } -} diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 72167761c88d..72a00ce052da 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -174,7 +174,6 @@ public class RcsUceAdapter { * Provides a one-time callback for the response to a UCE request. After this callback is called * by the framework, the reference to this callback will be discarded on the service side. * @see #requestCapabilities(Executor, List, CapabilitiesCallback) - * @hide */ public static class CapabilitiesCallback { @@ -226,10 +225,9 @@ public class RcsUceAdapter { * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not * available. This can happen if the ImsService has crashed, for example, or if the subscription * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. - * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void requestCapabilities(@CallbackExecutor Executor executor, + public void requestCapabilities(@NonNull @CallbackExecutor Executor executor, @NonNull List<Uri> contactNumbers, @NonNull CapabilitiesCallback c) throws ImsException { if (c == null) { @@ -289,7 +287,6 @@ public class RcsUceAdapter { * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not * available. This can happen if the ImsService has crashed, for example, or if the subscription * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. - * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @PublishState int getUcePublishState() throws ImsException { diff --git a/telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl b/telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl deleted file mode 100644 index 0ae6303f024e..000000000000 --- a/telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony.ims.aidl; - -import android.net.Uri; -import android.telephony.ims.RcsEventQueryParams; -import android.telephony.ims.RcsEventQueryResultDescriptor; -import android.telephony.ims.RcsFileTransferCreationParams; -import android.telephony.ims.RcsIncomingMessageCreationParams; -import android.telephony.ims.RcsMessageSnippet; -import android.telephony.ims.RcsMessageQueryParams; -import android.telephony.ims.RcsMessageQueryResultParcelable; -import android.telephony.ims.RcsOutgoingMessageCreationParams; -import android.telephony.ims.RcsParticipantQueryParams; -import android.telephony.ims.RcsParticipantQueryResultParcelable; -import android.telephony.ims.RcsQueryContinuationToken; -import android.telephony.ims.RcsThreadQueryParams; -import android.telephony.ims.RcsThreadQueryResultParcelable; - -/** - * RPC definition between RCS storage APIs and phone process. - * {@hide} - */ -interface IRcsMessage { - ///////////////////////// - // RcsMessageStore APIs - ///////////////////////// - RcsThreadQueryResultParcelable getRcsThreads(in RcsThreadQueryParams queryParams, String callingPackage); - - RcsThreadQueryResultParcelable getRcsThreadsWithToken( - in RcsQueryContinuationToken continuationToken, String callingPackage); - - RcsParticipantQueryResultParcelable getParticipants(in RcsParticipantQueryParams queryParams, String callingPackage); - - RcsParticipantQueryResultParcelable getParticipantsWithToken( - in RcsQueryContinuationToken continuationToken, String callingPackage); - - RcsMessageQueryResultParcelable getMessages(in RcsMessageQueryParams queryParams, String callingPackage); - - RcsMessageQueryResultParcelable getMessagesWithToken( - in RcsQueryContinuationToken continuationToken, String callingPackage); - - RcsEventQueryResultDescriptor getEvents(in RcsEventQueryParams queryParams, String callingPackage); - - RcsEventQueryResultDescriptor getEventsWithToken( - in RcsQueryContinuationToken continuationToken, String callingPackage); - - // returns true if the thread was successfully deleted - boolean deleteThread(int threadId, int threadType, String callingPackage); - - // Creates an Rcs1To1Thread and returns its row ID - int createRcs1To1Thread(int participantId, String callingPackage); - - // Creates an RcsGroupThread and returns its row ID - int createGroupThread(in int[] participantIds, String groupName, in Uri groupIcon, String callingPackage); - - ///////////////////////// - // RcsThread APIs - ///////////////////////// - - // Creates a new RcsIncomingMessage on the given thread and returns its row ID - int addIncomingMessage(int rcsThreadId, - in RcsIncomingMessageCreationParams rcsIncomingMessageCreationParams, String callingPackage); - - // Creates a new RcsOutgoingMessage on the given thread and returns its row ID - int addOutgoingMessage(int rcsThreadId, - in RcsOutgoingMessageCreationParams rcsOutgoingMessageCreationParams, String callingPackage); - - // TODO: modify RcsProvider URI's to allow deleting a message without specifying its thread - void deleteMessage(int rcsMessageId, boolean isIncoming, int rcsThreadId, boolean isGroup, String callingPackage); - - RcsMessageSnippet getMessageSnippet(int rcsThreadId, String callingPackage); - - ///////////////////////// - // Rcs1To1Thread APIs - ///////////////////////// - void set1To1ThreadFallbackThreadId(int rcsThreadId, long fallbackId, String callingPackage); - - long get1To1ThreadFallbackThreadId(int rcsThreadId, String callingPackage); - - int get1To1ThreadOtherParticipantId(int rcsThreadId, String callingPackage); - - ///////////////////////// - // RcsGroupThread APIs - ///////////////////////// - void setGroupThreadName(int rcsThreadId, String groupName, String callingPackage); - - String getGroupThreadName(int rcsThreadId, String callingPackage); - - void setGroupThreadIcon(int rcsThreadId, in Uri groupIcon, String callingPackage); - - Uri getGroupThreadIcon(int rcsThreadId, String callingPackage); - - void setGroupThreadOwner(int rcsThreadId, int participantId, String callingPackage); - - int getGroupThreadOwner(int rcsThreadId, String callingPackage); - - void setGroupThreadConferenceUri(int rcsThreadId, in Uri conferenceUri, String callingPackage); - - Uri getGroupThreadConferenceUri(int rcsThreadId, String callingPackage); - - void addParticipantToGroupThread(int rcsThreadId, int participantId, String callingPackage); - - void removeParticipantFromGroupThread(int rcsThreadId, int participantId, String callingPackage); - - ///////////////////////// - // RcsParticipant APIs - ///////////////////////// - - // Creates a new RcsParticipant and returns its rowId - int createRcsParticipant(String canonicalAddress, String alias, String callingPackage); - - String getRcsParticipantCanonicalAddress(int participantId, String callingPackage); - - String getRcsParticipantAlias(int participantId, String callingPackage); - - void setRcsParticipantAlias(int id, String alias, String callingPackage); - - String getRcsParticipantContactId(int participantId, String callingPackage); - - void setRcsParticipantContactId(int participantId, String contactId, String callingPackage); - - ///////////////////////// - // RcsMessage APIs - ///////////////////////// - void setMessageSubId(int messageId, boolean isIncoming, int subId, String callingPackage); - - int getMessageSubId(int messageId, boolean isIncoming, String callingPackage); - - void setMessageStatus(int messageId, boolean isIncoming, int status, String callingPackage); - - int getMessageStatus(int messageId, boolean isIncoming, String callingPackage); - - void setMessageOriginationTimestamp(int messageId, boolean isIncoming, long originationTimestamp, String callingPackage); - - long getMessageOriginationTimestamp(int messageId, boolean isIncoming, String callingPackage); - - void setGlobalMessageIdForMessage(int messageId, boolean isIncoming, String globalId, String callingPackage); - - String getGlobalMessageIdForMessage(int messageId, boolean isIncoming, String callingPackage); - - void setMessageArrivalTimestamp(int messageId, boolean isIncoming, long arrivalTimestamp, String callingPackage); - - long getMessageArrivalTimestamp(int messageId, boolean isIncoming, String callingPackage); - - void setMessageSeenTimestamp(int messageId, boolean isIncoming, long seenTimestamp, String callingPackage); - - long getMessageSeenTimestamp(int messageId, boolean isIncoming, String callingPackage); - - void setTextForMessage(int messageId, boolean isIncoming, String text, String callingPackage); - - String getTextForMessage(int messageId, boolean isIncoming, String callingPackage); - - void setLatitudeForMessage(int messageId, boolean isIncoming, double latitude, String callingPackage); - - double getLatitudeForMessage(int messageId, boolean isIncoming, String callingPackage); - - void setLongitudeForMessage(int messageId, boolean isIncoming, double longitude, String callingPackage); - - double getLongitudeForMessage(int messageId, boolean isIncoming, String callingPackage); - - // Returns the ID's of the file transfers attached to the given message - int[] getFileTransfersAttachedToMessage(int messageId, boolean isIncoming, String callingPackage); - - int getSenderParticipant(int messageId, String callingPackage); - - ///////////////////////// - // RcsOutgoingMessageDelivery APIs - ///////////////////////// - - // Returns the participant ID's that this message is intended to be delivered to - int[] getMessageRecipients(int messageId, String callingPackage); - - long getOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId, String callingPackage); - - void setOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId, long deliveredTimestamp, String callingPackage); - - long getOutgoingDeliverySeenTimestamp(int messageId, int participantId, String callingPackage); - - void setOutgoingDeliverySeenTimestamp(int messageId, int participantId, long seenTimestamp, String callingPackage); - - int getOutgoingDeliveryStatus(int messageId, int participantId, String callingPackage); - - void setOutgoingDeliveryStatus(int messageId, int participantId, int status, String callingPackage); - - ///////////////////////// - // RcsFileTransferPart APIs - ///////////////////////// - - // Performs the initial write to storage and returns the row ID. - int storeFileTransfer(int messageId, boolean isIncoming, - in RcsFileTransferCreationParams fileTransferCreationParams, String callingPackage); - - void deleteFileTransfer(int partId, String callingPackage); - - void setFileTransferSessionId(int partId, String sessionId, String callingPackage); - - String getFileTransferSessionId(int partId, String callingPackage); - - void setFileTransferContentUri(int partId, in Uri contentUri, String callingPackage); - - Uri getFileTransferContentUri(int partId, String callingPackage); - - void setFileTransferContentType(int partId, String contentType, String callingPackage); - - String getFileTransferContentType(int partId, String callingPackage); - - void setFileTransferFileSize(int partId, long fileSize, String callingPackage); - - long getFileTransferFileSize(int partId, String callingPackage); - - void setFileTransferTransferOffset(int partId, long transferOffset, String callingPackage); - - long getFileTransferTransferOffset(int partId, String callingPackage); - - void setFileTransferStatus(int partId, int transferStatus, String callingPackage); - - int getFileTransferStatus(int partId, String callingPackage); - - void setFileTransferWidth(int partId, int width, String callingPackage); - - int getFileTransferWidth(int partId, String callingPackage); - - void setFileTransferHeight(int partId, int height, String callingPackage); - - int getFileTransferHeight(int partId, String callingPackage); - - void setFileTransferLength(int partId, long length, String callingPackage); - - long getFileTransferLength(int partId, String callingPackage); - - void setFileTransferPreviewUri(int partId, in Uri uri, String callingPackage); - - Uri getFileTransferPreviewUri(int partId, String callingPackage); - - void setFileTransferPreviewType(int partId, String type, String callingPackage); - - String getFileTransferPreviewType(int partId, String callingPackage); - - ///////////////////////// - // RcsEvent APIs - ///////////////////////// - int createGroupThreadNameChangedEvent(long timestamp, int threadId, int originationParticipantId, String newName, String callingPackage); - - int createGroupThreadIconChangedEvent(long timestamp, int threadId, int originationParticipantId, in Uri newIcon, String callingPackage); - - int createGroupThreadParticipantJoinedEvent(long timestamp, int threadId, int originationParticipantId, int participantId, String callingPackage); - - int createGroupThreadParticipantLeftEvent(long timestamp, int threadId, int originationParticipantId, int participantId, String callingPackage); - - int createParticipantAliasChangedEvent(long timestamp, int participantId, String newAlias, String callingPackage); -}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index f3aea4978971..a3ce1b585f76 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -513,7 +513,7 @@ public class MmTelFeature extends ImsFeature { * @param callProfile The {@link ImsCallProfile} IMS call profile with details. * This can be null if no call information is available for the rejected call. * @param reason The {@link ImsReasonInfo} call rejection reason. - * * @hide + * @hide */ @SystemApi @TestApi public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile, diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 884a0bc7c06e..8e67621b2ea3 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -349,9 +349,8 @@ public class RcsFeature extends ImsFeature { * * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if * it is supported by the device. - * @hide */ - public RcsSipOptionsImplBase getOptionsExchangeImpl() { + public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() { // Base Implementation, override to implement functionality return new RcsSipOptionsImplBase(); } @@ -365,9 +364,8 @@ public class RcsFeature extends ImsFeature { * * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence * exchange if it is supported by the device. - * @hide */ - public RcsPresenceExchangeImplBase getPresenceExchangeImpl() { + public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() { // Base Implementation, override to implement functionality. return new RcsPresenceExchangeImplBase(); } diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java index fda295a27111..a24af2f74e27 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java @@ -17,6 +17,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.RemoteException; import android.telephony.ims.ImsException; import android.telephony.ims.aidl.IRcsFeatureListener; @@ -32,6 +34,8 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi +@TestApi public class RcsCapabilityExchange { /** Service is unknown. */ diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java index bb034489a296..f200ea2af2bc 100644 --- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -18,6 +18,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.ImsException; @@ -37,6 +39,8 @@ import java.util.List; * * @hide */ +@SystemApi +@TestApi public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { private static final String LOG_TAG = "RcsPresenceExchangeIB"; diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java index 1c68fc08529e..355c4dde75d8 100644 --- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java @@ -19,6 +19,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.ImsException; @@ -35,6 +37,8 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi +@TestApi public class RcsSipOptionsImplBase extends RcsCapabilityExchange { private static final String LOG_TAG = "RcsSipOptionsImplBase"; @@ -69,6 +73,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { */ public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; + /** + * Indicates that the remote user responded with a 400 BAD REQUEST response. + */ + public static final int RESPONSE_BAD_REQUEST = 5; + /** @hide*/ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "RESPONSE_", value = { @@ -77,7 +86,8 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { RESPONSE_TEMPORARILY_UNAVAILABLE, RESPONSE_REQUEST_TIMEOUT, RESPONSE_NOT_FOUND, - RESPONSE_DOES_NOT_EXIST_ANYWHERE + RESPONSE_DOES_NOT_EXIST_ANYWHERE, + RESPONSE_BAD_REQUEST }) public @interface SipResponseCode {} @@ -188,7 +198,6 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { * @param reason A non-null String containing the reason associated with the SIP code. * @param operationToken The token provided by the framework when * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called. - * */ public void respondToCapabilityRequestWithError(@NonNull Uri contactUri, @SipResponseCode int code, @NonNull String reason, int operationToken) { diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 6aa5a52d55d5..3f573c92d022 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -831,6 +831,11 @@ interface ITelephony { void disableIms(int slotId); /** + * Toggle framework IMS disables and enables. + */ + void resetIms(int slotIndex); + + /** * Get IImsMmTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature * as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback * interface. diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 48f785091764..d41a6c889afb 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -317,16 +317,8 @@ public class TelephonyIntents { "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED"; /** - * Broadcast action to notify radio bug. - * - * Requires the READ_PRIVILEGED_PHONE_STATE permission. - * - * @hide + * Broadcast sent when a user activity is detected. */ - public static final String ACTION_REPORT_RADIO_BUG = - "com.android.internal.telephony.ACTION_REPORT_RADIO_BUG"; - - // ACTION_REPORT_RADIO_BUG extra keys - public static final String EXTRA_SLOT_ID = "slotId"; - public static final String EXTRA_RADIO_BUG_TYPE = "radioBugType"; + public static final String ACTION_USER_ACTIVITY_NOTIFICATION = + "android.intent.action.USER_ACTIVITY_NOTIFICATION"; } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java index ae55a75d7e67..8559cb9f51f7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java @@ -30,10 +30,12 @@ import android.graphics.Rect; import android.view.Surface; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; import org.junit.Before; import org.junit.FixMethodOrder; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; @@ -50,6 +52,8 @@ import java.util.Collection; @LargeTest @RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 147659548) +@Ignore("Waiting bug feedback") public class SeamlessAppRotationTest extends FlickerTestBase { private int mBeginRotation; private int mEndRotation; diff --git a/tests/RcsTests/Android.bp b/tests/RcsTests/Android.bp deleted file mode 100644 index 8ee496066bb3..000000000000 --- a/tests/RcsTests/Android.bp +++ /dev/null @@ -1,17 +0,0 @@ -android_test { - name: "RcsTests", - // Only compile source java files in this apk. - srcs: ["src/**/*.java"], - platform_apis: true, - certificate: "platform", - libs: [ - "android.test.runner", - "android.test.base", - ], - static_libs: [ - "junit", - "androidx.test.rules", - "mockito-target-minus-junit4", - "truth-prebuilt", - ], -} diff --git a/tests/RcsTests/AndroidManifest.xml b/tests/RcsTests/AndroidManifest.xml deleted file mode 100644 index b1706a0a3629..000000000000 --- a/tests/RcsTests/AndroidManifest.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.tests.rcs"> - <application android:label="RCS Test"> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.tests.rcs"/> -</manifest> diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java deleted file mode 100644 index 6c311f99f695..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open 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.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.net.Uri; -import android.os.Parcel; -import android.telephony.ims.RcsGroupThreadIconChangedEvent; -import android.telephony.ims.RcsGroupThreadIconChangedEventDescriptor; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsGroupThreadIconChangedEventTest { - - @Test - public void testCanUnparcel() { - int rcsGroupThreadId = 1; - int rcsParticipantId = 2; - Uri newIconUri = Uri.parse("content://new_icon"); - - RcsGroupThreadIconChangedEventDescriptor iconChangedEventDescriptor = - new RcsGroupThreadIconChangedEventDescriptor(1234567890, rcsGroupThreadId, - rcsParticipantId, newIconUri); - - Parcel parcel = Parcel.obtain(); - iconChangedEventDescriptor.writeToParcel( - parcel, iconChangedEventDescriptor.describeContents()); - - parcel.setDataPosition(0); - - iconChangedEventDescriptor = - RcsGroupThreadIconChangedEventDescriptor.CREATOR.createFromParcel(parcel); - - RcsGroupThreadIconChangedEvent iconChangedEvent = - iconChangedEventDescriptor.createRcsEvent(null); - - assertThat(iconChangedEvent.getNewIcon()).isEqualTo(newIconUri); - assertThat(iconChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1); - assertThat(iconChangedEvent.getOriginatingParticipant().getId()).isEqualTo(2); - assertThat(iconChangedEvent.getTimestamp()).isEqualTo(1234567890); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java deleted file mode 100644 index a60dabb023f8..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open 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.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsGroupThreadNameChangedEvent; -import android.telephony.ims.RcsGroupThreadNameChangedEventDescriptor; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsGroupThreadNameChangedEventTest { - @Test - public void testCanUnparcel() { - String newName = "new name"; - - int rcsGroupThreadId = 1; - int rcsParticipantId = 2; - - RcsGroupThreadNameChangedEventDescriptor nameChangedEventDescriptor = - new RcsGroupThreadNameChangedEventDescriptor( - 1234567890, rcsGroupThreadId, rcsParticipantId, newName); - - Parcel parcel = Parcel.obtain(); - nameChangedEventDescriptor.writeToParcel( - parcel, nameChangedEventDescriptor.describeContents()); - - parcel.setDataPosition(0); - - nameChangedEventDescriptor = RcsGroupThreadNameChangedEventDescriptor.CREATOR - .createFromParcel(parcel); - - RcsGroupThreadNameChangedEvent nameChangedEvent = - nameChangedEventDescriptor.createRcsEvent(null); - - assertThat(nameChangedEvent.getNewName()).isEqualTo(newName); - assertThat(nameChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1); - assertThat(nameChangedEvent.getOriginatingParticipant().getId()).isEqualTo(2); - assertThat(nameChangedEvent.getTimestamp()).isEqualTo(1234567890); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java deleted file mode 100644 index 7b02cb1eaafa..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open 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.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsGroupThreadParticipantJoinedEvent; -import android.telephony.ims.RcsGroupThreadParticipantJoinedEventDescriptor; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsGroupThreadParticipantJoinedEventTest { - - @Test - public void testCanUnparcel() { - int rcsGroupThreadId = 1; - int rcsParticipantId = 2; - - RcsGroupThreadParticipantJoinedEventDescriptor participantJoinedEventDescriptor = - new RcsGroupThreadParticipantJoinedEventDescriptor( - 1234567890, rcsGroupThreadId, rcsParticipantId, rcsParticipantId); - - Parcel parcel = Parcel.obtain(); - participantJoinedEventDescriptor.writeToParcel( - parcel, participantJoinedEventDescriptor.describeContents()); - - parcel.setDataPosition(0); - - participantJoinedEventDescriptor = RcsGroupThreadParticipantJoinedEventDescriptor.CREATOR - .createFromParcel(parcel); - - RcsGroupThreadParticipantJoinedEvent participantJoinedEvent = - participantJoinedEventDescriptor.createRcsEvent(null); - - assertThat(participantJoinedEvent.getJoinedParticipant().getId()).isEqualTo(2); - assertThat(participantJoinedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1); - assertThat(participantJoinedEvent.getOriginatingParticipant().getId()).isEqualTo(2); - assertThat(participantJoinedEvent.getTimestamp()).isEqualTo(1234567890); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java deleted file mode 100644 index 51466bd98d60..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open 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.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsGroupThreadParticipantLeftEvent; -import android.telephony.ims.RcsGroupThreadParticipantLeftEventDescriptor; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsGroupThreadParticipantLeftEventTest { - @Test - public void testCanUnparcel() { - int rcsGroupThreadId = 1; - int rcsParticipantId = 2; - - RcsGroupThreadParticipantLeftEventDescriptor participantLeftEventDescriptor = - new RcsGroupThreadParticipantLeftEventDescriptor( - 1234567890, rcsGroupThreadId, rcsParticipantId, rcsParticipantId); - - Parcel parcel = Parcel.obtain(); - participantLeftEventDescriptor.writeToParcel( - parcel, participantLeftEventDescriptor.describeContents()); - - parcel.setDataPosition(0); - - // create from parcel - parcel.setDataPosition(0); - participantLeftEventDescriptor = RcsGroupThreadParticipantLeftEventDescriptor.CREATOR - .createFromParcel(parcel); - - RcsGroupThreadParticipantLeftEvent participantLeftEvent = - participantLeftEventDescriptor.createRcsEvent(null); - - assertThat(participantLeftEvent.getRcsGroupThread().getThreadId()).isEqualTo(1); - assertThat(participantLeftEvent.getLeavingParticipant().getId()).isEqualTo(2); - assertThat(participantLeftEvent.getTimestamp()).isEqualTo(1234567890); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java deleted file mode 100644 index 56830dff1ce5..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open 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.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsParticipantAliasChangedEvent; -import android.telephony.ims.RcsParticipantAliasChangedEventDescriptor; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsParticipantAliasChangedEventTest { - private static final String OLD_ALIAS = "old alias"; - private static final String NEW_ALIAS = "new alias"; - private int mParticipantId = 3; - - @Test - public void testCanUnparcel() { - RcsParticipantAliasChangedEventDescriptor aliasChangedEventDescriptor = - new RcsParticipantAliasChangedEventDescriptor( - 1234567890, mParticipantId, NEW_ALIAS); - - Parcel parcel = Parcel.obtain(); - aliasChangedEventDescriptor.writeToParcel( - parcel, aliasChangedEventDescriptor.describeContents()); - - parcel.setDataPosition(0); - - aliasChangedEventDescriptor = RcsParticipantAliasChangedEventDescriptor.CREATOR - .createFromParcel(parcel); - - RcsParticipantAliasChangedEvent aliasChangedEvent = - aliasChangedEventDescriptor.createRcsEvent(null); - - assertThat(aliasChangedEvent.getParticipant().getId()).isEqualTo(mParticipantId); - assertThat(aliasChangedEvent.getNewAlias()).isEqualTo(NEW_ALIAS); - assertThat(aliasChangedEvent.getTimestamp()).isEqualTo(1234567890); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java deleted file mode 100644 index 2d95513be069..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.tests.ims; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsParticipantQueryParams; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsParticipantQueryParamsTest { - - @Test - public void testCanUnparcel() { - RcsParticipantQueryParams rcsParticipantQueryParams = - new RcsParticipantQueryParams.Builder() - .setAliasLike("%alias_") - .setCanonicalAddressLike("_canonical%") - .setSortProperty(RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS) - .setSortDirection(true) - .setResultLimit(432) - .build(); - - - Parcel parcel = Parcel.obtain(); - rcsParticipantQueryParams.writeToParcel(parcel, - rcsParticipantQueryParams.describeContents()); - - parcel.setDataPosition(0); - rcsParticipantQueryParams = RcsParticipantQueryParams.CREATOR.createFromParcel( - parcel); - - assertThat(rcsParticipantQueryParams.getAliasLike()).isEqualTo("%alias_"); - assertThat(rcsParticipantQueryParams.getCanonicalAddressLike()).contains("_canonical%"); - assertThat(rcsParticipantQueryParams.getLimit()).isEqualTo(432); - assertThat(rcsParticipantQueryParams.getSortingProperty()).isEqualTo( - RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS); - assertThat(rcsParticipantQueryParams.getSortDirection()).isTrue(); - } -} diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java deleted file mode 100644 index 7a3e384020a1..000000000000 --- a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.tests.ims; - -import static android.telephony.ims.RcsThreadQueryParams.SORT_BY_TIMESTAMP; -import static android.telephony.ims.RcsThreadQueryParams.THREAD_TYPE_GROUP; - -import static com.google.common.truth.Truth.assertThat; - -import android.os.Parcel; -import android.telephony.ims.RcsParticipant; -import android.telephony.ims.RcsThreadQueryParams; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class RcsThreadQueryParamsTest { - - @Test - public void testCanUnparcel() { - RcsParticipant rcsParticipant = new RcsParticipant(null, 1); - RcsThreadQueryParams rcsThreadQueryParams = new RcsThreadQueryParams.Builder() - .setThreadType(THREAD_TYPE_GROUP) - .setParticipant(rcsParticipant) - .setResultLimit(50) - .setSortProperty(SORT_BY_TIMESTAMP) - .setSortDirection(true) - .build(); - - Parcel parcel = Parcel.obtain(); - rcsThreadQueryParams.writeToParcel(parcel, rcsThreadQueryParams.describeContents()); - - parcel.setDataPosition(0); - rcsThreadQueryParams = RcsThreadQueryParams.CREATOR.createFromParcel(parcel); - - assertThat(rcsThreadQueryParams.getThreadType()).isEqualTo(THREAD_TYPE_GROUP); - assertThat(rcsThreadQueryParams.getRcsParticipantsIds()) - .contains(rcsParticipant.getId()); - assertThat(rcsThreadQueryParams.getLimit()).isEqualTo(50); - assertThat(rcsThreadQueryParams.getSortingProperty()).isEqualTo(SORT_BY_TIMESTAMP); - assertThat(rcsThreadQueryParams.getSortDirection()).isTrue(); - } -} diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java index e566e44c811a..06c6301d66f3 100644 --- a/tests/net/common/java/android/net/LinkAddressTest.java +++ b/tests/net/common/java/android/net/LinkAddressTest.java @@ -326,26 +326,23 @@ public class LinkAddressTest { assertParcelSane(l, 6); } - /* @Test public void testDeprecationTime() { try { new LinkAddress(V6_ADDRESS, 64, 0, 456, - LinkAddress.LIFETIME_UNKNOWN, - SystemClock.elapsedRealtime() + 200000); + LinkAddress.LIFETIME_UNKNOWN, 100000L); fail("Only one time provided should cause exception"); } catch (IllegalArgumentException expected) { } try { new LinkAddress(V6_ADDRESS, 64, 0, 456, - SystemClock.elapsedRealtime() - 100000, - SystemClock.elapsedRealtime() - 200000); + 200000L, 100000L); fail("deprecation time later than expiration time should cause exception"); } catch (IllegalArgumentException expected) { } try { new LinkAddress(V6_ADDRESS, 64, 0, 456, - -2, SystemClock.elapsedRealtime()); + -2, 100000L); fail("negative deprecation time should cause exception"); } catch (IllegalArgumentException expected) { } } @@ -354,14 +351,13 @@ public class LinkAddressTest { public void testExpirationTime() { try { new LinkAddress(V6_ADDRESS, 64, 0, 456, - SystemClock.elapsedRealtime() + 200000, - LinkAddress.LIFETIME_UNKNOWN); + 200000L, LinkAddress.LIFETIME_UNKNOWN); fail("Only one time provided should cause exception"); } catch (IllegalArgumentException expected) { } try { new LinkAddress(V6_ADDRESS, 64, 0, 456, - SystemClock.elapsedRealtime() - 10000, -2); + 100000L, -2); fail("negative expiration time should cause exception"); } catch (IllegalArgumentException expected) { } } @@ -374,12 +370,12 @@ public class LinkAddressTest { // Test if deprecated bit was added/remove automatically based on the provided deprecation // time l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST, - SystemClock.elapsedRealtime() - 100000, LinkAddress.LIFETIME_PERMANENT); + 1L, LinkAddress.LIFETIME_PERMANENT); // Check if the flag is added automatically. assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0); l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST, - SystemClock.elapsedRealtime() + 100000, LinkAddress.LIFETIME_PERMANENT); + SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT); // Check if the flag is removed automatically. assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0); @@ -389,12 +385,10 @@ public class LinkAddressTest { assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0); l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST, - SystemClock.elapsedRealtime() - 100000, - SystemClock.elapsedRealtime() + 100000); + 1000L, SystemClock.elapsedRealtime() + 100000L); // Check if the permanent flag is removed assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0); - }*/ - + } private void assertGlobalPreferred(LinkAddress l, String msg) { assertTrue(msg, l.isGlobalPreferred()); diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 797fd83321f7..3e4f3d818840 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -269,6 +269,7 @@ public class NetworkCapabilitiesTest { .setUids(uids) .addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_NOT_METERED); + netCap.setOwnerUid(123); assertParcelingIsLossless(netCap); netCap.setSSID(TEST_SSID); assertParcelSane(netCap, 13); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 09cc69e83f41..a0a1352a6330 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -6313,12 +6313,24 @@ public class ConnectivityServiceTest { assertEquals(wifiLp, mService.getActiveLinkProperties()); } + @Test + public void testNetworkCapabilitiesRestrictedForCallerPermissions() { + int callerUid = Process.myUid(); + final NetworkCapabilities originalNc = new NetworkCapabilities(); + originalNc.setOwnerUid(callerUid); + + final NetworkCapabilities newNc = + mService.networkCapabilitiesRestrictedForCallerPermissions( + originalNc, Process.myPid(), callerUid); + + assertEquals(Process.INVALID_UID, newNc.getOwnerUid()); + } - private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid, - Set<UidRange> vpnRange) throws Exception { + private TestNetworkAgentWrapper establishVpn( + LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception { final TestNetworkAgentWrapper vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp); - vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid); + vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.connect(); mMockVpn.setUids(vpnRange); |