diff options
167 files changed, 1830 insertions, 4797 deletions
diff --git a/api/current.txt b/api/current.txt index 4db5cee1dc28..56b608c1a962 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11956,6 +11956,7 @@ package android.database.sqlite { public static final class SQLiteDatabase.OpenParams { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); + method public long getIdleConnectionTimeout(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); @@ -11969,6 +11970,7 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); } @@ -12026,6 +12028,7 @@ package android.database.sqlite { method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int); method public void onOpen(android.database.sqlite.SQLiteDatabase); method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int); + method public void setIdleConnectionTimeout(long); method public void setLookasideConfig(int, int); method public void setWriteAheadLoggingEnabled(boolean); } diff --git a/api/system-current.txt b/api/system-current.txt index 41f63535ddd2..cb80b170ea35 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12752,6 +12752,7 @@ package android.database.sqlite { public static final class SQLiteDatabase.OpenParams { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); + method public long getIdleConnectionTimeout(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); @@ -12765,6 +12766,7 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); } @@ -12822,6 +12824,7 @@ package android.database.sqlite { method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int); method public void onOpen(android.database.sqlite.SQLiteDatabase); method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int); + method public void setIdleConnectionTimeout(long); method public void setLookasideConfig(int, int); method public void setWriteAheadLoggingEnabled(boolean); } @@ -38650,6 +38653,7 @@ package android.provider { public final class TimeZoneRulesDataContract { field public static final java.lang.String AUTHORITY = "com.android.timezone"; + field public static final java.lang.String READER_PERMISSION = "android.permission.UPDATE_TIME_ZONE_RULES"; } public static final class TimeZoneRulesDataContract.Operation { diff --git a/api/test-current.txt b/api/test-current.txt index 87539ec87945..84eea3692959 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12000,6 +12000,7 @@ package android.database.sqlite { public static final class SQLiteDatabase.OpenParams { method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory(); method public android.database.DatabaseErrorHandler getErrorHandler(); + method public long getIdleConnectionTimeout(); method public int getLookasideSlotCount(); method public int getLookasideSlotSize(); method public int getOpenFlags(); @@ -12013,6 +12014,7 @@ package android.database.sqlite { method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler); + method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int); method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int); } @@ -12095,6 +12097,7 @@ package android.database.sqlite { method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int); method public void onOpen(android.database.sqlite.SQLiteDatabase); method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int); + method public void setIdleConnectionTimeout(long); method public void setLookasideConfig(int, int); method public void setWriteAheadLoggingEnabled(boolean); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d03b3474d268..4a4bab55f054 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4893,7 +4893,8 @@ public final class ActivityThread { // If the new config is the same as the config this Activity is already running with and // the override config also didn't change, then don't bother calling // onConfigurationChanged. - int diff = activity.mCurrentConfig.diff(newConfig); + final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig); + if (diff != 0 || !mResourcesManager.isSameResourcesOverrideConfig(activityToken, amOverrideConfig)) { // Always send the task-level config changes. For system-level configuration, if @@ -4981,6 +4982,14 @@ public final class ActivityThread { int configDiff = 0; + // This flag tracks whether the new configuration is fundamentally equivalent to the + // existing configuration. This is necessary to determine whether non-activity + // callbacks should receive notice when the only changes are related to non-public fields. + // We do not gate calling {@link #performActivityConfigurationChanged} based on this flag + // as that method uses the same check on the activity config override as well. + final boolean equivalent = config != null && mConfiguration != null + && (0 == mConfiguration.diffPublicOnly(config)); + synchronized (mResourcesManager) { if (mPendingConfiguration != null) { if (!mPendingConfiguration.isOtherSeqNewer(config)) { @@ -5037,7 +5046,7 @@ public final class ActivityThread { Activity a = (Activity) cb; performConfigurationChangedForActivity(mActivities.get(a.getActivityToken()), config); - } else { + } else if (!equivalent) { performConfigurationChanged(cb, config); } } diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java index 13f288ab7454..371cd127bd5e 100644 --- a/core/java/android/app/DexLoadReporter.java +++ b/core/java/android/app/DexLoadReporter.java @@ -28,6 +28,7 @@ import dalvik.system.VMRuntime; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -86,29 +87,50 @@ import java.util.Set; } @Override - public void report(List<String> dexPaths) { - if (dexPaths.isEmpty()) { + public void report(List<BaseDexClassLoader> classLoadersChain, List<String> classPaths) { + if (classLoadersChain.size() != classPaths.size()) { + Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch"); return; } + if (classPaths.isEmpty()) { + Slog.wtf(TAG, "Bad call to DexLoadReporter: empty dex paths"); + return; + } + + // The first element of classPaths is the list of dex files that should be registered. + // The classpath is represented as a list of dex files separated by File.pathSeparator. + String[] dexPathsForRegistration = classPaths.get(0).split(File.pathSeparator); + if (dexPathsForRegistration.length == 0) { + // No dex files to register. + return; + } + // Notify the package manager about the dex loads unconditionally. // The load might be for either a primary or secondary dex file. - notifyPackageManager(dexPaths); - // Check for secondary dex files and register them for profiling if - // possible. - registerSecondaryDexForProfiling(dexPaths); + notifyPackageManager(classLoadersChain, classPaths); + // Check for secondary dex files and register them for profiling if possible. + // Note that we only register the dex paths belonging to the first class loader. + registerSecondaryDexForProfiling(dexPathsForRegistration); } - private void notifyPackageManager(List<String> dexPaths) { + private void notifyPackageManager(List<BaseDexClassLoader> classLoadersChain, + List<String> classPaths) { + // Get the class loader names for the binder call. + List<String> classLoadersNames = new ArrayList<>(classPaths.size()); + for (BaseDexClassLoader bdc : classLoadersChain) { + classLoadersNames.add(bdc.getClass().getName()); + } String packageName = ActivityThread.currentPackageName(); try { ActivityThread.getPackageManager().notifyDexLoad( - packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet()); + packageName, classLoadersNames, classPaths, + VMRuntime.getRuntime().vmInstructionSet()); } catch (RemoteException re) { Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re); } } - private void registerSecondaryDexForProfiling(List<String> dexPaths) { + private void registerSecondaryDexForProfiling(String[] dexPaths) { if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) { return; } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 6f326de76150..595ecd201e57 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -44,8 +44,6 @@ import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Predicate; @@ -417,7 +415,12 @@ public class ResourcesManager { if (activityResources == null) { return overrideConfig == null; } else { - return Objects.equals(activityResources.overrideConfig, overrideConfig); + // The two configurations must either be equal or publicly equivalent to be + // considered the same. + return Objects.equals(activityResources.overrideConfig, overrideConfig) + || (overrideConfig != null && activityResources.overrideConfig != null + && 0 == overrideConfig.diffPublicOnly( + activityResources.overrideConfig)); } } } @@ -984,8 +987,6 @@ public class ResourcesManager { } } - invalidatePath("/"); - redirectResourcesToNewImplLocked(updatedResourceKeys); } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 64d687e9d3de..c9afd6b7e930 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -469,11 +469,19 @@ interface IPackageManager { * Notify the package manager that a list of dex files have been loaded. * * @param loadingPackageName the name of the package who performs the load - * @param dexPats the list of the dex files paths that have been loaded + * @param classLoadersNames the names of the class loaders present in the loading chain. The + * list encodes the class loader chain in the natural order. The first class loader has + * the second one as its parent and so on. The dex files present in the class path of the + * first class loader will be recorded in the usage file. + * @param classPaths the class paths corresponding to the class loaders names from + * {@param classLoadersNames}. The the first element corresponds to the first class loader + * and so on. A classpath is represented as a list of dex files separated by + * {@code File.pathSeparator}. + * The dex files found in the first class path will be recorded in the usage file. * @param loaderIsa the ISA of the loader process */ - oneway void notifyDexLoad(String loadingPackageName, in List<String> dexPaths, - String loaderIsa); + oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames, + in List<String> classPaths, String loaderIsa); /** * Register an application dex module with the package manager. diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index af2713199950..f7cccd56f079 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1318,7 +1318,19 @@ public final class Configuration implements Parcelable, Comparable<Configuration * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}. */ public int diff(Configuration delta) { - return diff(delta, false /* compareUndefined */); + return diff(delta, false /* compareUndefined */, false /* publicOnly */); + } + + /** + * Returns the diff against the provided {@link Configuration} excluding values that would + * publicly be equivalent, such as appBounds. + * @param delta {@link Configuration} to compare to. + * + * TODO(b/36812336): Remove once appBounds has been moved out of Configuration. + * {@hide} + */ + public int diffPublicOnly(Configuration delta) { + return diff(delta, false /* compareUndefined */, true /* publicOnly */); } /** @@ -1326,7 +1338,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * * @hide */ - public int diff(Configuration delta, boolean compareUndefined) { + public int diff(Configuration delta, boolean compareUndefined, boolean publicOnly) { int changed = 0; if ((compareUndefined || delta.fontScale > 0) && fontScale != delta.fontScale) { changed |= ActivityInfo.CONFIG_FONT_SCALE; @@ -1424,7 +1436,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration // Make sure that one of the values is not null and that they are not equal. if ((compareUndefined || delta.appBounds != null) && appBounds != delta.appBounds - && (appBounds == null || !appBounds.equals(delta.appBounds))) { + && (appBounds == null || (!publicOnly && !appBounds.equals(delta.appBounds)) + || (publicOnly && (appBounds.width() != delta.appBounds.width() + || appBounds.height() != delta.appBounds.height())))) { changed |= ActivityInfo.CONFIG_SCREEN_SIZE; } diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index 581fe7fce5eb..fdb702f01e9d 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -23,6 +23,7 @@ import android.os.UserHandle; import android.util.Log; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -330,7 +331,14 @@ public abstract class AbstractCursor implements CrossProcessCursor { public int getColumnIndexOrThrow(String columnName) { final int index = getColumnIndex(columnName); if (index < 0) { - throw new IllegalArgumentException("column '" + columnName + "' does not exist"); + String availableColumns = ""; + try { + availableColumns = Arrays.toString(getColumnNames()); + } catch (Exception e) { + Log.d(TAG, "Cannot collect column names for debug purposes", e); + } + throw new IllegalArgumentException("column '" + columnName + + "' does not exist. Available columns: " + availableColumns); } return index; } diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 6ce8787e6c38..b66bf18fca1d 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -16,7 +16,6 @@ package android.database.sqlite; -import android.app.ActivityManager; import android.database.sqlite.SQLiteDebug.DbStats; import android.os.CancellationSignal; import android.os.Handler; @@ -24,7 +23,6 @@ import android.os.Looper; import android.os.Message; import android.os.OperationCanceledException; import android.os.SystemClock; -import android.os.SystemProperties; import android.util.Log; import android.util.PrefixPrinter; import android.util.Printer; @@ -84,15 +82,6 @@ public final class SQLiteConnectionPool implements Closeable { // and logging a message about the connection pool being busy. private static final long CONNECTION_POOL_BUSY_MILLIS = 30 * 1000; // 30 seconds - // TODO b/63398887 Move to SQLiteGlobal - private static final long IDLE_CONNECTION_CLOSE_DELAY_MILLIS = SystemProperties - .getInt("persist.debug.sqlite.idle_connection_close_delay", 30000); - - // TODO b/63398887 STOPSHIP. - // Temporarily enabled for testing across a broader set of dogfood devices. - private static final boolean CLOSE_IDLE_CONNECTIONS = SystemProperties - .getBoolean("persist.debug.sqlite.close_idle_connections", true); - private final CloseGuard mCloseGuard = CloseGuard.get(); private final Object mLock = new Object(); @@ -167,16 +156,12 @@ public final class SQLiteConnectionPool implements Closeable { private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) { mConfiguration = new SQLiteDatabaseConfiguration(configuration); - // Disable lookaside allocator on low-RAM devices - if (ActivityManager.isLowRamDeviceStatic()) { - mConfiguration.lookasideSlotCount = 0; - mConfiguration.lookasideSlotSize = 0; - } setMaxConnectionPoolSizeLocked(); - - // Do not close idle connections for in-memory databases - if (CLOSE_IDLE_CONNECTIONS && !configuration.isInMemoryDb()) { - setupIdleConnectionHandler(Looper.getMainLooper(), IDLE_CONNECTION_CLOSE_DELAY_MILLIS); + // If timeout is set, setup idle connection handler + // In case of MAX_VALUE - idle connections are never closed + if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) { + setupIdleConnectionHandler(Looper.getMainLooper(), + mConfiguration.idleConnectionTimeoutMs); } } @@ -214,6 +199,12 @@ public final class SQLiteConnectionPool implements Closeable { // This might throw if the database is corrupt. mAvailablePrimaryConnection = openConnectionLocked(mConfiguration, true /*primaryConnection*/); // might throw + // Mark it released so it can be closed after idle timeout + synchronized (mLock) { + if (mIdleConnectionHandler != null) { + mIdleConnectionHandler.connectionReleased(mAvailablePrimaryConnection); + } + } // Mark the pool as being open for business. mIsOpen = true; @@ -1023,12 +1014,12 @@ public final class SQLiteConnectionPool implements Closeable { } /** - * Set up the handler based on the provided looper and delay. + * Set up the handler based on the provided looper and timeout. */ @VisibleForTesting - public void setupIdleConnectionHandler(Looper looper, long delayMs) { + public void setupIdleConnectionHandler(Looper looper, long timeoutMs) { synchronized (mLock) { - mIdleConnectionHandler = new IdleConnectionHandler(looper, delayMs); + mIdleConnectionHandler = new IdleConnectionHandler(looper, timeoutMs); } } @@ -1089,6 +1080,10 @@ public final class SQLiteConnectionPool implements Closeable { printer.println(" Lookaside config: sz=" + mConfiguration.lookasideSlotSize + " cnt=" + mConfiguration.lookasideSlotCount); } + if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) { + printer.println( + " Idle connection timeout: " + mConfiguration.idleConnectionTimeoutMs); + } printer.println(" Available primary connection:"); if (mAvailablePrimaryConnection != null) { mAvailablePrimaryConnection.dump(indentedPrinter, verbose); @@ -1155,11 +1150,11 @@ public final class SQLiteConnectionPool implements Closeable { } private class IdleConnectionHandler extends Handler { - private final long mDelay; + private final long mTimeout; - IdleConnectionHandler(Looper looper, long delay) { + IdleConnectionHandler(Looper looper, long timeout) { super(looper); - mDelay = delay; + mTimeout = timeout; } @Override @@ -1172,14 +1167,14 @@ public final class SQLiteConnectionPool implements Closeable { if (closeAvailableConnectionLocked(msg.what)) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Closed idle connection " + mConfiguration.label + " " + msg.what - + " after " + mDelay); + + " after " + mTimeout); } } } } void connectionReleased(SQLiteConnection con) { - sendEmptyMessageDelayed(con.getConnectionId(), mDelay); + sendEmptyMessageDelayed(con.getConnectionId(), mTimeout); } void connectionAcquired(SQLiteConnection con) { diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index af6df1554a86..5b6efd4dcffe 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseErrorHandler; @@ -30,6 +31,7 @@ import android.database.sqlite.SQLiteDebug.DbStats; import android.os.CancellationSignal; import android.os.Looper; import android.os.OperationCanceledException; +import android.os.SystemProperties; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; @@ -77,21 +79,21 @@ public final class SQLiteDatabase extends SQLiteClosable { private static final int EVENT_DB_CORRUPT = 75004; + // TODO b/63398887 STOPSHIP. + // Temporarily enabled for testing across a broader set of dogfood devices. + private static final boolean DEBUG_CLOSE_IDLE_CONNECTIONS = SystemProperties + .getBoolean("persist.debug.sqlite.close_idle_connections", true); + // Stores reference to all databases opened in the current process. // (The referent Object is not used at this time.) // INVARIANT: Guarded by sActiveDatabases. - private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = - new WeakHashMap<SQLiteDatabase, Object>(); + private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>(); // Thread-local for database sessions that belong to this database. // Each thread has its own database session. // INVARIANT: Immutable. - private final ThreadLocal<SQLiteSession> mThreadSession = new ThreadLocal<SQLiteSession>() { - @Override - protected SQLiteSession initialValue() { - return createSession(); - } - }; + private final ThreadLocal<SQLiteSession> mThreadSession = ThreadLocal + .withInitial(this::createSession); // The optional factory to use when creating new Cursors. May be null. // INVARIANT: Immutable. @@ -261,12 +263,29 @@ public final class SQLiteDatabase extends SQLiteClosable { private SQLiteDatabase(final String path, final int openFlags, CursorFactory cursorFactory, DatabaseErrorHandler errorHandler, - int lookasideSlotSize, int lookasideSlotCount) { + int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs) { mCursorFactory = cursorFactory; mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler(); mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags); mConfigurationLocked.lookasideSlotSize = lookasideSlotSize; mConfigurationLocked.lookasideSlotCount = lookasideSlotCount; + // Disable lookaside allocator on low-RAM devices + if (ActivityManager.isLowRamDeviceStatic()) { + mConfigurationLocked.lookasideSlotCount = 0; + mConfigurationLocked.lookasideSlotSize = 0; + } + long effectiveTimeoutMs = Long.MAX_VALUE; + // Never close idle connections for in-memory databases + if (!mConfigurationLocked.isInMemoryDb()) { + // First, check app-specific value. Otherwise use defaults + // -1 in idleConnectionTimeoutMs indicates unset value + if (idleConnectionTimeoutMs >= 0) { + effectiveTimeoutMs = idleConnectionTimeoutMs; + } else if (DEBUG_CLOSE_IDLE_CONNECTIONS) { + effectiveTimeoutMs = SQLiteGlobal.getIdleConnectionTimeout(); + } + } + mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs; } @Override @@ -694,7 +713,8 @@ public final class SQLiteDatabase extends SQLiteClosable { Preconditions.checkArgument(openParams != null, "OpenParams cannot be null"); SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags, openParams.mCursorFactory, openParams.mErrorHandler, - openParams.mLookasideSlotSize, openParams.mLookasideSlotCount); + openParams.mLookasideSlotSize, openParams.mLookasideSlotCount, + openParams.mIdleConnectionTimeout); db.open(); return db; } @@ -720,7 +740,7 @@ public final class SQLiteDatabase extends SQLiteClosable { */ public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory, @DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) { - SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1); + SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1); db.open(); return db; } @@ -2267,14 +2287,17 @@ public final class SQLiteDatabase extends SQLiteClosable { private final DatabaseErrorHandler mErrorHandler; private final int mLookasideSlotSize; private final int mLookasideSlotCount; + private long mIdleConnectionTimeout; private OpenParams(int openFlags, CursorFactory cursorFactory, - DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount) { + DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount, + long idleConnectionTimeout) { mOpenFlags = openFlags; mCursorFactory = cursorFactory; mErrorHandler = errorHandler; mLookasideSlotSize = lookasideSlotSize; mLookasideSlotCount = lookasideSlotCount; + mIdleConnectionTimeout = idleConnectionTimeout; } /** @@ -2330,6 +2353,17 @@ public final class SQLiteDatabase extends SQLiteClosable { } /** + * Returns maximum number of milliseconds that SQLite connection is allowed to be idle + * before it is closed and removed from the pool. + * <p>If the value isn't set, the timeout defaults to the system wide timeout + * + * @return timeout in milliseconds or -1 if the value wasn't set. + */ + public long getIdleConnectionTimeout() { + return mIdleConnectionTimeout; + } + + /** * Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with * {@code this} parameters. * @hide @@ -2345,6 +2379,7 @@ public final class SQLiteDatabase extends SQLiteClosable { public static final class Builder { private int mLookasideSlotSize = -1; private int mLookasideSlotCount = -1; + private long mIdleConnectionTimeout = -1; private int mOpenFlags; private CursorFactory mCursorFactory; private DatabaseErrorHandler mErrorHandler; @@ -2474,13 +2509,29 @@ public final class SQLiteDatabase extends SQLiteClosable { } /** + * Sets the maximum number of milliseconds that SQLite connection is allowed to be idle + * before it is closed and removed from the pool. + * + * @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE} + * to allow unlimited idle connections. + */ + @NonNull + public Builder setIdleConnectionTimeout( + @IntRange(from = 0) long idleConnectionTimeoutMs) { + Preconditions.checkArgument(idleConnectionTimeoutMs >= 0, + "idle connection timeout cannot be negative"); + mIdleConnectionTimeout = idleConnectionTimeoutMs; + return this; + } + + /** * Creates an instance of {@link OpenParams} with the options that were previously set * on this builder */ @NonNull public OpenParams build() { return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize, - mLookasideSlotCount); + mLookasideSlotCount, mIdleConnectionTimeout); } } } diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index 7f09b73adaa7..34c9b3395d1a 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -94,14 +94,21 @@ public final class SQLiteDatabaseConfiguration { * * <p>If negative, the default lookaside configuration will be used */ - public int lookasideSlotSize; + public int lookasideSlotSize = -1; /** * The total number of lookaside memory slots per database connection * * <p>If negative, the default lookaside configuration will be used */ - public int lookasideSlotCount; + public int lookasideSlotCount = -1; + + /** + * The number of milliseconds that SQLite connection is allowed to be idle before it + * is closed and removed from the pool. + * <p>By default, idle connections are not closed + */ + public long idleConnectionTimeoutMs = Long.MAX_VALUE; /** * Creates a database configuration with the required parameters for opening a @@ -122,8 +129,6 @@ public final class SQLiteDatabaseConfiguration { // Set default values for optional parameters. maxSqlCacheSize = 25; locale = Locale.getDefault(); - lookasideSlotSize = -1; - lookasideSlotCount = -1; } /** @@ -164,6 +169,7 @@ public final class SQLiteDatabaseConfiguration { customFunctions.addAll(other.customFunctions); lookasideSlotSize = other.lookasideSlotSize; lookasideSlotCount = other.lookasideSlotCount; + idleConnectionTimeoutMs = other.idleConnectionTimeoutMs; } /** diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java index 922d11b6ae65..571656a22240 100644 --- a/core/java/android/database/sqlite/SQLiteGlobal.java +++ b/core/java/android/database/sqlite/SQLiteGlobal.java @@ -124,4 +124,15 @@ public final class SQLiteGlobal { com.android.internal.R.integer.db_connection_pool_size)); return Math.max(2, value); } + + /** + * The default number of milliseconds that SQLite connection is allowed to be idle before it + * is closed and removed from the pool. + */ + public static int getIdleConnectionTimeout() { + return SystemProperties.getInt("debug.sqlite.idle_connection_timeout", + Resources.getSystem().getInteger( + com.android.internal.R.integer.db_default_idle_connection_timeout)); + } + } diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index c19db82a81f7..dfaf714963eb 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -195,6 +195,26 @@ public abstract class SQLiteOpenHelper { } /** + * Sets the maximum number of milliseconds that SQLite connection is allowed to be idle + * before it is closed and removed from the pool. + * + * <p>This method should be called from the constructor of the subclass, + * before opening the database + * + * @param idleConnectionTimeoutMs timeout in milliseconds. Use {@link Long#MAX_VALUE} value + * to allow unlimited idle connections. + */ + public void setIdleConnectionTimeout(@IntRange(from = 0) final long idleConnectionTimeoutMs) { + synchronized (this) { + if (mDatabase != null && mDatabase.isOpen()) { + throw new IllegalStateException( + "Connection timeout setting cannot be changed after opening the database"); + } + mOpenParamsBuilder.setIdleConnectionTimeout(idleConnectionTimeoutMs); + } + } + + /** * Create and/or open a database that will be used for reading and writing. * The first time this is called, the database will be opened and * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index 6825d363b918..c7654c9e74e1 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -412,6 +412,9 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession // If no sequences are pending, fire #onClosed immediately mSequenceDrainer.beginDrain(); } + if (mInput != null) { + mInput.release(); + } } /** diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java index d5b72aa9ab21..fcb3d8641717 100644 --- a/core/java/android/hardware/radio/RadioManager.java +++ b/core/java/android/hardware/radio/RadioManager.java @@ -16,8 +16,10 @@ package android.hardware.radio; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; @@ -1571,6 +1573,7 @@ public class RadioManager { * <li>{@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails, </li> * </ul> */ + @RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO) public int listModules(List<ModuleProperties> modules) { if (modules == null) { Log.e(TAG, "the output list must not be empty"); @@ -1611,6 +1614,7 @@ public class RadioManager { * Can be null if default handler is OK. * @return a valid {@link RadioTuner} interface in case of success or null in case of error. */ + @RequiresPermission(Manifest.permission.ACCESS_BROADCAST_RADIO) public RadioTuner openTuner(int moduleId, BandConfig config, boolean withAudio, RadioTuner.Callback callback, Handler handler) { if (callback == null) { diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index ace37486647c..1e41eea925a5 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,10 @@ package android.net.nsd; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkStringNotEmpty; + import android.annotation.SdkConstant; import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; @@ -240,12 +244,12 @@ public final class NsdManager { return name; } + private static int FIRST_LISTENER_KEY = 1; + private final INsdManager mService; private final Context mContext; - private static final int INVALID_LISTENER_KEY = 0; - private static final int BUSY_LISTENER_KEY = -1; - private int mListenerKey = 1; + private int mListenerKey = FIRST_LISTENER_KEY; private final SparseArray mListenerMap = new SparseArray(); private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); @@ -311,7 +315,6 @@ public final class NsdManager { public void onServiceFound(NsdServiceInfo serviceInfo); public void onServiceLost(NsdServiceInfo serviceInfo); - } /** Interface for callback invocation for service registration */ @@ -342,8 +345,9 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - if (DBG) Log.d(TAG, "received " + nameOf(message.what)); - switch (message.what) { + final int what = message.what; + final int key = message.arg2; + switch (what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); return; @@ -356,19 +360,26 @@ public final class NsdManager { default: break; } - Object listener = getListener(message.arg2); + final Object listener; + final NsdServiceInfo ns; + synchronized (mMapLock) { + listener = mListenerMap.get(key); + ns = mServiceMap.get(key); + } if (listener == null) { Log.d(TAG, "Stale key " + message.arg2); return; } - NsdServiceInfo ns = getNsdService(message.arg2); - switch (message.what) { + if (DBG) { + Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); + } + switch (what) { case DISCOVER_SERVICES_STARTED: String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); break; case DISCOVER_SERVICES_FAILED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; @@ -381,16 +392,16 @@ public final class NsdManager { case STOP_DISCOVERY_FAILED: // TODO: failure to stop discovery should be internal and retried internally, as // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: @@ -398,7 +409,7 @@ public final class NsdManager { (NsdServiceInfo) message.obj); break; case UNREGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: @@ -408,11 +419,11 @@ public final class NsdManager { ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); break; default: @@ -422,40 +433,27 @@ public final class NsdManager { } } - // if the listener is already in the map, reject it. Otherwise, add it and - // return its key. + private int nextListenerKey() { + // Ensure mListenerKey >= FIRST_LISTENER_KEY; + mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); + return mListenerKey; + } + + // Assert that the listener is not in the map, then add it and returns its key private int putListener(Object listener, NsdServiceInfo s) { - if (listener == null) return INVALID_LISTENER_KEY; - int key; + checkListener(listener); + final int key; synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return BUSY_LISTENER_KEY; - } - do { - key = mListenerKey++; - } while (key == INVALID_LISTENER_KEY); + checkArgument(valueIndex == -1, "listener already in use"); + key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); } return key; } - private Object getListener(int key) { - if (key == INVALID_LISTENER_KEY) return null; - synchronized (mMapLock) { - return mListenerMap.get(key); - } - } - - private NsdServiceInfo getNsdService(int key) { - synchronized (mMapLock) { - return mServiceMap.get(key); - } - } - private void removeListener(int key) { - if (key == INVALID_LISTENER_KEY) return; synchronized (mMapLock) { mListenerMap.remove(key); mServiceMap.remove(key); @@ -463,16 +461,15 @@ public final class NsdManager { } private int getListenerKey(Object listener) { + checkListener(listener); synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return mListenerMap.keyAt(valueIndex); - } + checkArgument(valueIndex != -1, "listener not registered"); + return mListenerMap.keyAt(valueIndex); } - return INVALID_LISTENER_KEY; } - private String getNsdServiceInfoType(NsdServiceInfo s) { + private static String getNsdServiceInfoType(NsdServiceInfo s) { if (s == null) return "?"; return s.getServiceType(); } @@ -482,7 +479,9 @@ public final class NsdManager { */ private void init() { final Messenger messenger = getMessenger(); - if (messenger == null) throw new RuntimeException("Failed to initialize"); + if (messenger == null) { + fatal("Failed to obtain service Messenger"); + } HandlerThread t = new HandlerThread("NsdManager"); t.start(); mHandler = new ServiceHandler(t.getLooper()); @@ -490,10 +489,15 @@ public final class NsdManager { try { mConnected.await(); } catch (InterruptedException e) { - Log.e(TAG, "interrupted wait at init"); + fatal("Interrupted wait at init"); } } + private static void fatal(String msg) { + Log.e(TAG, msg); + throw new RuntimeException(msg); + } + /** * Register a service to be discovered by other services. * @@ -513,23 +517,10 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkArgument(serviceInfo.getPort() > 0, "Invalid port number"); + checkServiceInfo(serviceInfo); + checkProtocol(protocolType); int key = putListener(listener, serviceInfo); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); } @@ -548,12 +539,6 @@ public final class NsdManager { */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("listener not registered"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); } @@ -586,25 +571,13 @@ public final class NsdManager { * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkStringNotEmpty(serviceType, "Service type cannot be empty"); + checkProtocol(protocolType); NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); int key = putListener(listener, s); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); } @@ -626,12 +599,6 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("service discovery not active on listener"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); } @@ -645,19 +612,8 @@ public final class NsdManager { * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - + checkServiceInfo(serviceInfo); int key = putListener(listener, serviceInfo); - - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); } @@ -671,10 +627,10 @@ public final class NsdManager { } /** - * Get a reference to NetworkService handler. This is used to establish + * Get a reference to NsdService handler. This is used to establish * an AsyncChannel communication with the service * - * @return Messenger pointing to the NetworkService handler + * @return Messenger pointing to the NsdService handler */ private Messenger getMessenger() { try { @@ -683,4 +639,18 @@ public final class NsdManager { throw e.rethrowFromSystemServer(); } } + + private static void checkListener(Object listener) { + checkNotNull(listener, "listener cannot be null"); + } + + private static void checkProtocol(int protocolType) { + checkArgument(protocolType == PROTOCOL_DNS_SD, "Unsupported protocol"); + } + + private static void checkServiceInfo(NsdServiceInfo serviceInfo) { + checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); + checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty"); + checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); + } } diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index f762a052cb41..d5216e73ba66 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -153,6 +153,14 @@ public interface IBinder { * caller returns immediately, without waiting for a result from the * callee. Applies only if the caller and callee are in different * processes. + * + * <p>The system provides special ordering semantics for multiple oneway calls + * being made to the same IBinder object: these calls will be dispatched in the + * other process one at a time, with the same order as the original calls. These + * are still dispatched by the IPC thread pool, so may execute on different threads, + * but the next one will not be dispatched until the previous one completes. This + * ordering is not guaranteed for calls on different IBinder objects or when mixing + * oneway and non-oneway calls on the same IBinder object.</p> */ int FLAG_ONEWAY = 0x00000001; diff --git a/core/java/android/provider/TimeZoneRulesDataContract.java b/core/java/android/provider/TimeZoneRulesDataContract.java index 33d25880226e..7a5ae1d7af41 100644 --- a/core/java/android/provider/TimeZoneRulesDataContract.java +++ b/core/java/android/provider/TimeZoneRulesDataContract.java @@ -41,6 +41,12 @@ public final class TimeZoneRulesDataContract { private static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); /** + * The permission that the reader of the ContentProvider must possess. + */ + public static final String READER_PERMISSION = + android.Manifest.permission.UPDATE_TIME_ZONE_RULES; + + /** * Defines fields exposed through the {@link Operation#CONTENT_URI} for describing a time zone * distro operation. */ diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 029f66e1d670..ed583907123b 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -64,19 +64,17 @@ public final class FontConfig { private final int mWeight; private final boolean mIsItalic; private Uri mUri; - private final String mFallbackFor; /** * @hide */ public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes, - int weight, boolean isItalic, String fallbackFor) { + int weight, boolean isItalic) { mFontName = fontName; mTtcIndex = ttcIndex; mAxes = axes; mWeight = weight; mIsItalic = isItalic; - mFallbackFor = fallbackFor; } /** @@ -127,10 +125,6 @@ public final class FontConfig { public void setUri(@NonNull Uri uri) { mUri = uri; } - - public String getFallbackFor() { - return mFallbackFor; - } } /** diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java index 3a3646b99bdf..c17cfd500827 100644 --- a/core/java/android/text/style/TextAppearanceSpan.java +++ b/core/java/android/text/style/TextAppearanceSpan.java @@ -70,7 +70,11 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl TextAppearance_textSize, -1); mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0); - mTypeface = a.getFont(com.android.internal.R.styleable.TextAppearance_fontFamily); + if (!context.isRestricted() && context.canLoadUnsafeResources()) { + mTypeface = a.getFont(com.android.internal.R.styleable.TextAppearance_fontFamily); + } else { + mTypeface = null; + } if (mTypeface != null) { mFamilyName = null; } else { diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java index 0122e49eb462..6342c8bcb85e 100644 --- a/core/java/android/util/AtomicFile.java +++ b/core/java/android/util/AtomicFile.java @@ -214,10 +214,10 @@ public class AtomicFile { * Gets the last modified time of the atomic file. * {@hide} * - * @return last modified time in milliseconds since epoch. - * @throws IOException + * @return last modified time in milliseconds since epoch. Returns zero if + * the file does not exist or an I/O error is encountered. */ - public long getLastModifiedTime() throws IOException { + public long getLastModifiedTime() { if (mBackupName.exists()) { return mBackupName.lastModified(); } diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java index df9c27b9df14..1168eec3b66f 100644 --- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java +++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java @@ -94,8 +94,8 @@ public class AmbientDisplayConfiguration { } public boolean alwaysOnEnabled(int user) { - return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user) - && alwaysOnAvailable(); + return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user) && alwaysOnAvailable() + && !accessibilityInversionEnabled(user); } public boolean alwaysOnAvailable() { @@ -103,10 +103,18 @@ public class AmbientDisplayConfiguration { && ambientDisplayAvailable(); } + public boolean alwaysOnAvailableForUser(int user) { + return alwaysOnAvailable() && !accessibilityInversionEnabled(user); + } + public String ambientDisplayComponent() { return mContext.getResources().getString(R.string.config_dozeComponent); } + private boolean accessibilityInversionEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user); + } + private boolean ambientDisplayAvailable() { return !TextUtils.isEmpty(ambientDisplayComponent()); } diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index 61c57c8007bd..0df420b417fd 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -19,6 +19,7 @@ package com.android.internal.os; import android.os.Trace; import dalvik.system.DelegateLastClassLoader; +import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader; /** @@ -31,6 +32,7 @@ public class ClassLoaderFactory { private ClassLoaderFactory() {} private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); + private static final String DEX_CLASS_LOADER_NAME = DexClassLoader.class.getName(); private static final String DELEGATE_LAST_CLASS_LOADER_NAME = DelegateLastClassLoader.class.getName(); @@ -44,12 +46,14 @@ public class ClassLoaderFactory { } /** - * Returns true if {@code name} is the encoding for the PathClassLoader. + * Returns true if {@code name} is the encoding for either PathClassLoader or DexClassLoader. + * The two class loaders are grouped together because they have the same behaviour. */ public static boolean isPathClassLoaderName(String name) { // For null values we default to PathClassLoader. This cover the case when packages // don't specify any value for their class loaders. - return name == null || PATH_CLASS_LOADER_NAME.equals(name); + return name == null || PATH_CLASS_LOADER_NAME.equals(name) || + DEX_CLASS_LOADER_NAME.equals(name); } /** diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 71e48e4f9b3d..e6c45c1451a9 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -263,7 +263,7 @@ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"օգտագործել օրացույցը"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"ուղարկել և դիտել SMS-ները"</string> - <string name="permgrouplab_storage" msgid="1971118770546336966">"Հիշողություն"</string> + <string name="permgrouplab_storage" msgid="1971118770546336966">"Տարածք"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր սարքում պահվող մյուս ֆայլերը"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Խոսափող"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ձայնագրել"</string> diff --git a/core/res/res/values-mcc310-mnc260-af/strings.xml b/core/res/res/values-mcc310-mnc260-af/strings.xml deleted file mode 100644 index ee051c5d21ec..000000000000 --- a/core/res/res/values-mcc310-mnc260-af/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Om oproepe te maak en boodskappe oor Wi-Fi te stuur, vra jou diensverskaffer eers om hierdie diens op te stel. Skakel Wi-Fi-oproepe dan weer in Instellings aan."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registreer by jou diensverskaffer"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-oproep"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-am/strings.xml b/core/res/res/values-mcc310-mnc260-am/strings.xml deleted file mode 100644 index 74f711a26b6a..000000000000 --- a/core/res/res/values-mcc310-mnc260-am/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"በWi-Fi ላይ ጥሪዎችን ለማድረግ እና መልዕክቶችን ለመላክ መጀመሪያ የአገልግሎት አቅራቢዎ ይህን አገልግሎት እንዲያዘጋጅልዎ መጠየቅ አለብዎት። ከዚያ ከቅንብሮች ሆነው እንደገና የWi-Fi ጥሪን ያብሩ።"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"የአገልግሎት አቅራቢዎ ጋር ይመዝገቡ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"የ%s Wi-Fi ጥሪ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ar/strings.xml b/core/res/res/values-mcc310-mnc260-ar/strings.xml deleted file mode 100644 index 5a8429584c51..000000000000 --- a/core/res/res/values-mcc310-mnc260-ar/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مشغّل شبكة الجوّال أولاً إعداد هذا الجهاز، ثم شغّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"التسجيل لدى مشغّل شبكة الجوّال"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s جارٍ الاتصال عبر Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-az/strings.xml b/core/res/res/values-mcc310-mnc260-az/strings.xml deleted file mode 100644 index 32d21c56fca5..000000000000 --- a/core/res/res/values-mcc310-mnc260-az/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Operatorla qeydiyyatdan keçin"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Zəngi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml deleted file mode 100644 index 67509405d09e..000000000000 --- a/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Da biste upućivali pozive i slali poruke preko Wi-Fi-ja, prvo zatražite od mobilnog operatera da vam omogući ovu uslugu. Zatim u Podešavanjima ponovo uključite Pozivanje preko Wi-Fi-ja."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrujte se kod mobilnog operatera"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi pozivanje preko operatera %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-be/strings.xml b/core/res/res/values-mcc310-mnc260-be/strings.xml deleted file mode 100644 index 497366b9db58..000000000000 --- a/core/res/res/values-mcc310-mnc260-be/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Зарэгіструйцеся ў свайго аператара"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi-тэлефанія %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-bg/strings.xml b/core/res/res/values-mcc310-mnc260-bg/strings.xml deleted file mode 100644 index a671120871e1..000000000000 --- a/core/res/res/values-mcc310-mnc260-bg/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"За да извършвате обаждания и да изпращате съобщения през Wi-Fi, първо помолете оператора си да настрои тази услуга. След това включете отново функцията за обаждания през Wi-Fi от настройките."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Регистриране с оператора ви"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s – обаждания през Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-bn/strings.xml b/core/res/res/values-mcc310-mnc260-bn/strings.xml deleted file mode 100644 index 67955d59839c..000000000000 --- a/core/res/res/values-mcc310-mnc260-bn/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi এর মাধ্যমে কল করতে ও বার্তা পাঠাতে, প্রথমে আপনার পরিষেবা প্রদানকারীকে এই পরিষেবার সেট আপ করার বিষয়ে জিজ্ঞাসা করুন। তারপরে আবার সেটিংস থেকে Wi-Fi কলিং চালু করুন।"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"আপনার পরিষেবা প্রদানকারীকে নথিভুক্ত করুন"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi কলিং"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-bs/strings.xml b/core/res/res/values-mcc310-mnc260-bs/strings.xml deleted file mode 100644 index 64e486289f94..000000000000 --- a/core/res/res/values-mcc310-mnc260-bs/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Da biste pozivali i slali poruke preko Wi-Fi-ja, prvo zatražite od operatera da postavi tu uslugu. Potom u Postavkama ponovo uključite Wi-Fi pozivanje."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrirajte se kod svog operatera"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi pozivanje preko operatera %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ca/strings.xml b/core/res/res/values-mcc310-mnc260-ca/strings.xml deleted file mode 100644 index 8ce8dc8bb6a4..000000000000 --- a/core/res/res/values-mcc310-mnc260-ca/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Per fer trucades i enviar missatges per Wi-Fi, primer has de demanar a l\'operador de telefonia mòbil que configuri aquest servei. Després, torna a activar les trucades per Wi-Fi des de Configuració."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registra\'t amb el teu operador de telefonia mòbil"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Trucada de Wi-Fi de: %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-cs/strings.xml b/core/res/res/values-mcc310-mnc260-cs/strings.xml deleted file mode 100644 index 61ba268899bb..000000000000 --- a/core/res/res/values-mcc310-mnc260-cs/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Chcete-li volat a odesílat textové zprávy přes síť Wi-Fi, nejprve požádejte operátora, aby vám tuto službu nastavil. Poté volání přes Wi-Fi opět zapněte v Nastavení."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrace u operátora"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Volání přes Wi-Fi: %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-da/strings.xml b/core/res/res/values-mcc310-mnc260-da/strings.xml deleted file mode 100644 index 0c612e5d3f0c..000000000000 --- a/core/res/res/values-mcc310-mnc260-da/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Hvis du vil foretage opkald og sende beskeder via Wi-Fi, skal du først anmode dit mobilselskab om at konfigurere denne tjeneste. Derefter skal du slå Wi-Fi-opkald til igen fra Indstillinger."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrer dig hos dit mobilselskab"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-opkald"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-de/strings.xml b/core/res/res/values-mcc310-mnc260-de/strings.xml deleted file mode 100644 index b9cbb489af02..000000000000 --- a/core/res/res/values-mcc310-mnc260-de/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Um über WLAN telefonieren und Nachrichten senden zu können, bitte zuerst deinen Mobilfunkanbieter, diesen Dienst einzurichten. Aktiviere die Option \"Anrufe über WLAN\" dann erneut über die Einstellungen."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registriere dich bei deinem Mobilfunkanbieter."</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Anrufe über WLAN"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-el/strings.xml b/core/res/res/values-mcc310-mnc260-el/strings.xml deleted file mode 100644 index b4cd123bfae4..000000000000 --- a/core/res/res/values-mcc310-mnc260-el/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Για να κάνετε κλήσεις και να στέλνετε μηνύματα μέσω Wi-Fi, ζητήστε πρώτα από την εταιρεία κινητής τηλεφωνίας να ρυθμίσει την υπηρεσία. Στη συνέχεια, ενεργοποιήστε ξανά τη λειτουργία κλήσεων μέσω Wi-Fi από τις Ρυθμίσεις."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Εγγραφείτε μέσω της εταιρείας κινητής τηλεφωνίας"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Κλήση Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml deleted file mode 100644 index 1d300eab69d9..000000000000 --- a/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Register with your operator"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml deleted file mode 100644 index 1d300eab69d9..000000000000 --- a/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Register with your operator"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml deleted file mode 100644 index 1d300eab69d9..000000000000 --- a/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Register with your operator"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml deleted file mode 100644 index 6398c02af1b7..000000000000 --- a/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para realizar llamadas o enviar mensajes por Wi-Fi, primero solicítale al proveedor que instale el servicio. Luego, vuelve a activar las llamadas por Wi-Fi desde Configuración."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Regístrate con tu proveedor."</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Llamada por Wi-Fi de %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-es/strings.xml b/core/res/res/values-mcc310-mnc260-es/strings.xml deleted file mode 100644 index e95911629b96..000000000000 --- a/core/res/res/values-mcc310-mnc260-es/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para hacer llamadas y enviar mensajes por Wi-Fi, debes pedir antes a tu operador que configure este servicio. Una vez hecho esto, vuelva a activar las llamadas Wi-Fi en Ajustes."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Regístrate con tu operador"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Llamada Wi-Fi de %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-et/strings.xml b/core/res/res/values-mcc310-mnc260-et/strings.xml deleted file mode 100644 index 231013006bb9..000000000000 --- a/core/res/res/values-mcc310-mnc260-et/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Üle WiFi-võrgu helistamiseks ja sõnumite saatmiseks paluge operaatoril esmalt see teenus seadistada. Seejärel lülitage WiFi-kõned menüüs Seaded uuesti sisse."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registreeruge operaatori juures"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WiFi kaudu helistamine"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-eu/strings.xml b/core/res/res/values-mcc310-mnc260-eu/strings.xml deleted file mode 100644 index 8fb03d4422d3..000000000000 --- a/core/res/res/values-mcc310-mnc260-eu/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi bidez deiak egiteko eta mezuak bidaltzeko, eskatu operadoreari zerbitzu hori gaitzeko. Ondoren, aktibatu Wi-Fi bidezko deiak Ezarpenak atalean."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Erregistratu operadorearekin"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi bidezko deiak"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-fa/strings.xml b/core/res/res/values-mcc310-mnc260-fa/strings.xml deleted file mode 100644 index 659a0dd89998..000000000000 --- a/core/res/res/values-mcc310-mnc260-fa/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"برای برقراری تماس و ارسال پیام از طریق Wi-Fi، ابتدا از شرکت مخابراتیتان درخواست کنید این سرویس را راهاندازی کند. سپس دوباره از تنظیمات، تماس Wi-Fi را روشن کنید."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ثبت نام با شرکت مخابراتی شما"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"تماس %s Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-fi/strings.xml b/core/res/res/values-mcc310-mnc260-fi/strings.xml deleted file mode 100644 index 1eecb61f8826..000000000000 --- a/core/res/res/values-mcc310-mnc260-fi/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Jos haluat soittaa puheluita ja lähettää viestejä Wi-Fin kautta, pyydä ensin operaattoriasi ottamaan tämä palvelu käyttöön. Ota sitten Wi-Fi-puhelut käyttöön asetuksissa."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Rekisteröidy operaattorisi asiakkaaksi."</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi-puhelut: %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml deleted file mode 100644 index c767039b2a46..000000000000 --- a/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Pour effectuer des appels et envoyer des messages par Wi-Fi, demandez tout d\'abord à votre fournisseur de services de configurer ce service. Réactivez ensuite les appels Wi-Fi dans les paramètres."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Inscrivez-vous auprès de votre fournisseur de services"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Appels Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-fr/strings.xml b/core/res/res/values-mcc310-mnc260-fr/strings.xml deleted file mode 100644 index 1de93cab9c18..000000000000 --- a/core/res/res/values-mcc310-mnc260-fr/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Pour effectuer des appels et envoyer des messages via le Wi-Fi, demandez tout d\'abord à votre opérateur de configurer ce service. Réactivez ensuite les appels Wi-Fi dans les paramètres."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Inscrivez-vous auprès de votre opérateur."</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Appels Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-gl/strings.xml b/core/res/res/values-mcc310-mnc260-gl/strings.xml deleted file mode 100644 index 2747ab3b90b3..000000000000 --- a/core/res/res/values-mcc310-mnc260-gl/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para facer chamadas e enviar mensaxes a través da wifi, primeiro pídelle ao teu operador que configure este servizo. A continuación, activa de novo as chamadas wifi en Configuración."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Rexístrate co teu operador"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Chamadas wifi de %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-gu/strings.xml b/core/res/res/values-mcc310-mnc260-gu/strings.xml deleted file mode 100644 index d02d5add685b..000000000000 --- a/core/res/res/values-mcc310-mnc260-gu/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi પર કૉલ્સ કરવા અને સંદેશા મોકલવા માટે, પહેલા તમારા કેરીઅરને આ સેવા સેટ કરવા માટે કહો. પછી સેટિંગ્સમાંથી Wi-Fi કૉલિંગ ચાલુ કરો."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"તમારા કેરીઅર સાથે નોંધણી કરો"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi કૉલિંગ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-hi/strings.xml b/core/res/res/values-mcc310-mnc260-hi/strings.xml deleted file mode 100644 index a19f51ad35e8..000000000000 --- a/core/res/res/values-mcc310-mnc260-hi/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"अपने वाहक के साथ पंजीकृत करें"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s वाई-फ़ाई कॉलिंग"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-hr/strings.xml b/core/res/res/values-mcc310-mnc260-hr/strings.xml deleted file mode 100644 index dc48a1e21201..000000000000 --- a/core/res/res/values-mcc310-mnc260-hr/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Da biste telefonirali i slali pozive putem Wi-Fi-ja, morate tražiti od mobilnog operatera da vam postavi tu uslugu. Zatim ponovo uključite Wi-Fi pozive u Postavkama."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrirajte se kod mobilnog operatera"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi pozivanje"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-hu/strings.xml b/core/res/res/values-mcc310-mnc260-hu/strings.xml deleted file mode 100644 index ef6a2fc033ef..000000000000 --- a/core/res/res/values-mcc310-mnc260-hu/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Ha Wi-Fi-n szeretne telefonálni és üzenetet küldeni, kérje meg szolgáltatóját, hogy állítsa be ezt a szolgáltatást. Ezután a Beállítások menüben kapcsolhatja be újra a Wi-Fi-hívást."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Regisztráljon a szolgáltatójánál"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-hívás"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-hy/strings.xml b/core/res/res/values-mcc310-mnc260-hy/strings.xml deleted file mode 100644 index 0a37df22811e..000000000000 --- a/core/res/res/values-mcc310-mnc260-hy/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi-ի միջոցով զանգեր կատարելու և հաղորդագրություններ ուղարկելու համար նախ դիմեք ձեր օպերատորին՝ ծառայությունը կարգավորելու համար: Ապա նորից միացրեք Wi-Fi զանգերը Կարգավորումներում:"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Գրանցվեք օպերատորի մոտ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi զանգեր"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-in/strings.xml b/core/res/res/values-mcc310-mnc260-in/strings.xml deleted file mode 100644 index 4da068ea32d0..000000000000 --- a/core/res/res/values-mcc310-mnc260-in/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Harap daftarkan ke operator"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Panggilan Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-is/strings.xml b/core/res/res/values-mcc310-mnc260-is/strings.xml deleted file mode 100644 index 1fd14d4b7e78..000000000000 --- a/core/res/res/values-mcc310-mnc260-is/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Til að hringja og senda skilaboð yfir Wi-Fi þarftu fyrst að biðja símafyrirtækið þitt um að setja þá þjónustu upp. Kveiktu síðan á Wi-Fi símtölum í stillingunum."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Skráðu þig hjá símafyrirtækinu"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi símtöl"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-it/strings.xml b/core/res/res/values-mcc310-mnc260-it/strings.xml deleted file mode 100644 index 6a7dec50e774..000000000000 --- a/core/res/res/values-mcc310-mnc260-it/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Per effettuare chiamate e inviare messaggi tramite Wi-Fi, è necessario prima chiedere all\'operatore telefonico di attivare il servizio. Successivamente, riattiva le chiamate Wi-Fi dalle Impostazioni."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrati con il tuo operatore"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Chiamata Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-iw/strings.xml b/core/res/res/values-mcc310-mnc260-iw/strings.xml deleted file mode 100644 index 1bcce94dde1c..000000000000 --- a/core/res/res/values-mcc310-mnc260-iw/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"כדי להתקשר ולשלוח הודעות ברשת Wi-Fi, תחילה יש לבקש מהספק להגדיר את השירות. לאחר מכן, יש להפעיל שוב התקשרות Wi-Fi מ\'הגדרות\'."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"הירשם אצל הספק"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"שיחות Wi-Fi של %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ja/strings.xml b/core/res/res/values-mcc310-mnc260-ja/strings.xml deleted file mode 100644 index 05a333b597ae..000000000000 --- a/core/res/res/values-mcc310-mnc260-ja/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi経由で音声通話の発信やメッセージの送信を行うには、携帯通信会社にWi-Fiサービスを申し込んだ上で、設定画面でWi-Fi発信を再度ONにしてください。"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"携帯通信会社に登録してください"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi通話(%s)"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ka/strings.xml b/core/res/res/values-mcc310-mnc260-ka/strings.xml deleted file mode 100644 index dbb28228b1d9..000000000000 --- a/core/res/res/values-mcc310-mnc260-ka/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi-ს მეშვეობით ზარების განხორციელების ან შეტყობინების გაგზავნისათვის, პირველ რიგში დაეკითხეთ თქვენს ოპერატორს აღნიშნულ მომსახურებაზე. შემდეგ ხელახლა ჩართეთ Wi-Fi ზარები პარამეტრებიდან."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"დაარეგისტრირეთ თქვენი ოპერატორი"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s დარეკვა Wi-Fi-ს მეშვეობით"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-kk/strings.xml b/core/res/res/values-mcc310-mnc260-kk/strings.xml deleted file mode 100644 index 80eebfcc3d60..000000000000 --- a/core/res/res/values-mcc310-mnc260-kk/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi арқылы қоңырау шалу және хабарларды жіберу үшін алдымен жабдықтаушыңыздан осы қызметті орнатуды сұраңыз. Содан кейін Параметрлерден Wi-Fi қоңырау шалуын іске қосыңыз."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Жабдықтаушыңыз арқылы тіркелу"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi арқылы қоңырау шалу"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-km/strings.xml b/core/res/res/values-mcc310-mnc260-km/strings.xml deleted file mode 100644 index e3cd1b232039..000000000000 --- a/core/res/res/values-mcc310-mnc260-km/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"ដើម្បីធ្វើការហៅ និងផ្ញើសារតាម Wi-Fi ដំបូងឡើយអ្នកត្រូវស្នើឲ្យក្រុមហ៊ុនរបស់អ្នកដំឡើងសេវាកម្មនេះសិន។ បន្ទាប់មកបើកការហៅតាម Wi-Fi ម្តងទៀតចេញពីការកំណត់។"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ចុះឈ្មោះជាមួយក្រុមហ៊ុនរបស់អ្នក"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"ការហៅតាមរយៈ Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-kn/strings.xml b/core/res/res/values-mcc310-mnc260-kn/strings.xml deleted file mode 100644 index 0a9d58dfc26e..000000000000 --- a/core/res/res/values-mcc310-mnc260-kn/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi ಬಳಸಿಕೊಂಡು ಕರೆ ಮಾಡಲು ಮತ್ತು ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು, ಮೊದಲು ಈ ಸಾಧನವನ್ನು ಹೊಂದಿಸಲು ನಿಮ್ಮ ವಾಹಕವನ್ನು ಕೇಳಿ. ತದನಂತರ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಮತ್ತೆ Wi-Fi ಆನ್ ಮಾಡಿ."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ನಿಮ್ಮ ವಾಹಕದಲ್ಲಿ ನೋಂದಾಯಿಸಿಕೊಳ್ಳಿ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi ಕರೆ ಮಾಡುವಿಕೆ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ko/strings.xml b/core/res/res/values-mcc310-mnc260-ko/strings.xml deleted file mode 100644 index 5581235609e0..000000000000 --- a/core/res/res/values-mcc310-mnc260-ko/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi를 사용하여 전화를 걸고 메시지를 보내려면 먼저 이동통신사에 문의하여 이 기능을 설정해야 합니다. 그런 다음 설정에서 Wi-Fi 통화를 사용 설정하시기 바랍니다."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"이동통신사에 등록"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 통화"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ky/strings.xml b/core/res/res/values-mcc310-mnc260-ky/strings.xml deleted file mode 100644 index 775542d32488..000000000000 --- a/core/res/res/values-mcc310-mnc260-ky/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi аркылуу чалууларды аткарып жана билдирүүлөрдү жөнөтүү үчүн адегенде операторуңуздан бул кызматты орнотушун сураныңыз. Андан соң, Жөндөөлөрдөн Wi-Fi чалууну кайра күйгүзүңүз."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Операторуңузга катталыңыз"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Чалуу"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-lo/strings.xml b/core/res/res/values-mcc310-mnc260-lo/strings.xml deleted file mode 100644 index 49f79016cc72..000000000000 --- a/core/res/res/values-mcc310-mnc260-lo/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"ເພື່ອໂທ ແລະສົ່ງຂໍ້ຄວາມຢູ່ເທິງ Wi-Fi, ກ່ອນອື່ນໝົດໃຫ້ຖ້າມຜູ້ໃຫ້ບໍລິການເຄືອຂ່າຍຂອງທ່ານ ເພື່ອຕັ້ງການບໍລິການນີ້. ຈາກນັ້ນເປີດການໂທ Wi-Fi ອີກຈາກການຕັ້ງຄ່າ."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ລົງທະບຽນກັບຜູ້ໃຫ້ບໍລິການເຄືອຂ່າຍຂອງທ່ານ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"ການໂທ %s Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-lt/strings.xml b/core/res/res/values-mcc310-mnc260-lt/strings.xml deleted file mode 100644 index 4c3ebb7bc6e1..000000000000 --- a/core/res/res/values-mcc310-mnc260-lt/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Jei norite skambinti ir siųsti pranešimus „Wi-Fi“ ryšiu, pirmiausia paprašykite operatoriaus nustatyti šią paslaugą. Tada vėl įjunkite skambinimą „Wi-Fi“ ryšiu „Nustatymų“ skiltyje."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Užregistruokite pas operatorių"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"„%s“ „Wi-Fi“ skambinimas"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-lv/strings.xml b/core/res/res/values-mcc310-mnc260-lv/strings.xml deleted file mode 100644 index 23d8ca0764e3..000000000000 --- a/core/res/res/values-mcc310-mnc260-lv/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Lai veiktu zvanus un sūtītu īsziņas Wi-Fi tīklā, vispirms lūdziet mobilo sakaru operatoru iestatīt šo pakalpojumu. Pēc tam iestatījumos vēlreiz ieslēdziet Wi-Fi zvanus."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Reģistrēt to pie sava mobilo sakaru operatora"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi zvani"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-mk/strings.xml b/core/res/res/values-mcc310-mnc260-mk/strings.xml deleted file mode 100644 index 878b7afc71a3..000000000000 --- a/core/res/res/values-mcc310-mnc260-mk/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"За повикување и испраќање пораки преку Wi-Fi, прво побарајте од операторот да ви ја постави оваа услуга. Потоа повторно вклучете повикување преку Wi-Fi во Поставки."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Регистрирајте се со операторот"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Повикување преку Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ml/strings.xml b/core/res/res/values-mcc310-mnc260-ml/strings.xml deleted file mode 100644 index a94680d128b4..000000000000 --- a/core/res/res/values-mcc310-mnc260-ml/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"വൈഫൈ വഴി കോളുകൾ വിളിക്കാനും സന്ദേശങ്ങൾ അയയ്ക്കാനും ആദ്യം നിങ്ങളുടെ കാരിയറോട് ഈ സേവനം സജ്ജമാക്കാൻ ആവശ്യപ്പെടുക. ക്രമീകരണത്തിൽ നിന്ന് വീണ്ടും വൈഫൈ കോളിംഗ് ഓണാക്കുക."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"നിങ്ങളുടെ കാരിയറിൽ രജിസ്റ്റർ ചെയ്യുക"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s വൈഫൈ കോളിംഗ്"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-mn/strings.xml b/core/res/res/values-mcc310-mnc260-mn/strings.xml deleted file mode 100644 index 4c97e2ebb697..000000000000 --- a/core/res/res/values-mcc310-mnc260-mn/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi-аар дуудлага хийх болон мессеж илгээхээр бол эхлээд оператороосоо энэ төхөөрөмжийг тохируулж өгөхийг хүсээрэй. Дараа нь Тохиргооноос Wi-Fi дуудлага хийх үйлдлийг асаагаарай."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Операторт бүртгүүлэх"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Дуудлага"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-mr/strings.xml b/core/res/res/values-mcc310-mnc260-mr/strings.xml deleted file mode 100644 index 06eceffc0269..000000000000 --- a/core/res/res/values-mcc310-mnc260-mr/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"आपल्या वाहकासह नोंदणी करा"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s वाय-फाय कॉलिंग"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ms/strings.xml b/core/res/res/values-mcc310-mnc260-ms/strings.xml deleted file mode 100644 index dafb3bdd09b3..000000000000 --- a/core/res/res/values-mcc310-mnc260-ms/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Untuk membuat panggilan dan menghantar mesej melalui Wi-Fi, mula-mula minta pembawa anda untuk menyediakan perkhidmatan ini. Kemudian hidupkan panggilan Wi-Fi semula daripada Tetapan."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Daftar dengan pembawa anda"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Panggilan Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-my/strings.xml b/core/res/res/values-mcc310-mnc260-my/strings.xml deleted file mode 100644 index 25ea19158f78..000000000000 --- a/core/res/res/values-mcc310-mnc260-my/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"ဝိုင်ဖိုင်သုံး၍ ဖုန်းခေါ်ဆိုရန်နှင့် မက်စေ့ဂျ်များပို့ရန်၊ ဤဝန်ဆောင်မှုအား စတင်သုံးနိုင်ရန်အတွက် သင့် မိုဘိုင်းဝန်ဆောင်မှုအား ဦးစွာမေးမြန်းပါ။ ထို့နောက် ဆက်တင်မှတဆင့် ဝိုင်ဖိုင် ခေါ်ဆိုမှုအား ထပ်ဖွင့်ပါ။"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"သင့် မိုဘိုင်းဝန်ဆောင်မှုဖြင့် မှတ်ပုံတင်ရန်"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ဝိုင်ဖိုင် ခေါ်ဆိုမှု"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-nb/strings.xml b/core/res/res/values-mcc310-mnc260-nb/strings.xml deleted file mode 100644 index 9918996d8efd..000000000000 --- a/core/res/res/values-mcc310-mnc260-nb/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"For å ringe og sende meldinger over Wi-Fi må du først be operatøren om å konfigurere denne tjenesten. Deretter slår du på Wi-Fi-anrop igjen fra Innstillinger."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrer deg hos operatøren din"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-anrop"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ne/strings.xml b/core/res/res/values-mcc310-mnc260-ne/strings.xml deleted file mode 100644 index 6fb7b505853f..000000000000 --- a/core/res/res/values-mcc310-mnc260-ne/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi बाट कल गर्न र सन्देशहरू पठाउन, सबभन्दा पहिला यो सेवा सेटअप गर्न तपाईँको वाहकलाई भन्नुहोस्। त्यसपछि फेरि सेटिङहरूबाट Wi-Fi कलिङ सक्रिय पार्नुहोस्।"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"तपाईँको वाहकसँग दर्ता गर्नुहोस्"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi कलिङ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-nl/strings.xml b/core/res/res/values-mcc310-mnc260-nl/strings.xml deleted file mode 100644 index ac4961cf96b0..000000000000 --- a/core/res/res/values-mcc310-mnc260-nl/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via \'Instellingen\'."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registreren bij je provider"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Bellen via wifi van %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-pa/strings.xml b/core/res/res/values-mcc310-mnc260-pa/strings.xml deleted file mode 100644 index 00266810dd64..000000000000 --- a/core/res/res/values-mcc310-mnc260-pa/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi ਤੇ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਹ ਸੇਵਾ ਸੈਟ ਅਪ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਵਿੱਚੋਂ Wi-Fi ਕਾਲਿੰਗ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ।"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi ਕਾਲਿੰਗ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-pl/strings.xml b/core/res/res/values-mcc310-mnc260-pl/strings.xml deleted file mode 100644 index b7f512d1932e..000000000000 --- a/core/res/res/values-mcc310-mnc260-pl/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Aby dzwonić i wysyłać wiadomości przez Wi-Fi, poproś swojego operatora o skonfigurowanie tej usługi. Potem ponownie włącz połączenia przez Wi-Fi w Ustawieniach."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Zarejestruj u operatora"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Połączenia przez Wi-Fi (%s)"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml deleted file mode 100644 index bad49c3771f2..000000000000 --- a/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Faça registro na sua operadora"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s chamada Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml deleted file mode 100644 index 18e3801874d1..000000000000 --- a/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as chamadas por Wi-Fi."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registar-se junto do seu operador"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Chamadas por Wi-Fi da %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-pt/strings.xml b/core/res/res/values-mcc310-mnc260-pt/strings.xml deleted file mode 100644 index bad49c3771f2..000000000000 --- a/core/res/res/values-mcc310-mnc260-pt/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Faça registro na sua operadora"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s chamada Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ro/strings.xml b/core/res/res/values-mcc310-mnc260-ro/strings.xml deleted file mode 100644 index 6b865a299684..000000000000 --- a/core/res/res/values-mcc310-mnc260-ro/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Pentru a apela și a trimite mesaje prin Wi-Fi, mai întâi solicitați configurarea acestui serviciu la operator. Apoi, activați din nou apelarea prin Wi-Fi din Setări."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Înregistrați-vă la operatorul dvs."</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Apelare prin Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ru/strings.xml b/core/res/res/values-mcc310-mnc260-ru/strings.xml deleted file mode 100644 index 829c477aa101..000000000000 --- a/core/res/res/values-mcc310-mnc260-ru/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Чтобы совершать звонки и отправлять сообщения по Wi-Fi, необходимо сначала обратиться к оператору связи и подключить эту услугу. После этого вы сможете снова выбрать этот параметр в настройках."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Укажите оператора и зарегистрируйтесь"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Звонки по Wi-Fi (%s)"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-si/strings.xml b/core/res/res/values-mcc310-mnc260-si/strings.xml deleted file mode 100644 index de009011030d..000000000000 --- a/core/res/res/values-mcc310-mnc260-si/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi හරහා ඇමතුම් සිදු කිරීමට සහ පණිවිඩ යැවීමට, පළමුව මෙම සේවාව පිහිටුවන ලෙස ඔබේ වාහකයෙන් ඉල්ලන්න. අනතුරුව සැකසීම් වෙතින් Wi-Fi ඇමතුම නැවත ක්රියාත්මක කරන්න."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ඔබගේ වාහකය සමඟ ලියාපදිංචි වන්න"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi අමතමින්"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sk/strings.xml b/core/res/res/values-mcc310-mnc260-sk/strings.xml deleted file mode 100644 index eb8b5f8f21fc..000000000000 --- a/core/res/res/values-mcc310-mnc260-sk/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Ak chcete volať a odosielať správy prostredníctvom siete Wi-Fi, kontaktujte najskôr svojho operátora v súvislosti s nastavením tejto služby. Potom opäť zapnite v Nastaveniach volanie cez Wi-Fi."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrujte sa so svojím operátorom"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Volanie siete Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sl/strings.xml b/core/res/res/values-mcc310-mnc260-sl/strings.xml deleted file mode 100644 index ae30c5a568d4..000000000000 --- a/core/res/res/values-mcc310-mnc260-sl/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Če želite klicati ali pošiljati sporočila prek omrežja Wi-Fi, se najprej obrnite na operaterja, da nastavi to storitev. Nato v nastavitvah znova vklopite klicanje prek omrežja Wi-Fi."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registracija pri operaterju"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Klicanje prek Wi-Fi-ja (%s)"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sq/strings.xml b/core/res/res/values-mcc310-mnc260-sq/strings.xml deleted file mode 100644 index 84ac15368cdc..000000000000 --- a/core/res/res/values-mcc310-mnc260-sq/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Për të bërë telefonata dhe për të dërguar mesazhe me Wi-Fi, në fillim kërkoji operatorit celular ta konfigurojë këtë shërbim. Më pas aktivizo përsëri telefonatat me Wi-Fi, nga Cilësimet."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Regjistrohu me operatorin tënd celular"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Telefonatat me Wi-Fi nga %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sr/strings.xml b/core/res/res/values-mcc310-mnc260-sr/strings.xml deleted file mode 100644 index 92c6f35cc60f..000000000000 --- a/core/res/res/values-mcc310-mnc260-sr/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Да бисте упућивали позиве и слали поруке преко Wi-Fi-ја, прво затражите од мобилног оператера да вам омогући ову услугу. Затим у Подешавањима поново укључите Позивање преко Wi-Fi-ја."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Региструјте се код мобилног оператера"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi позивање преко оператера %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sv/strings.xml b/core/res/res/values-mcc310-mnc260-sv/strings.xml deleted file mode 100644 index 632a2ce859ab..000000000000 --- a/core/res/res/values-mcc310-mnc260-sv/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Om du vill ringa samtal och skicka meddelanden via Wi-Fi ber du först operatören att konfigurera tjänsten. Därefter kan du aktivera Wi-Fi-samtal på nytt från Inställningar."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Registrera dig hos operatören"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-samtal"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-sw/strings.xml b/core/res/res/values-mcc310-mnc260-sw/strings.xml deleted file mode 100644 index eecf6d26a751..000000000000 --- a/core/res/res/values-mcc310-mnc260-sw/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Ili upige simu na kutuma ujumbe kupitia Wi-Fi, mwambie mtoa huduma wako asanidi huduma hii kwanza. Kisha uwashe tena upigaji simu kwa Wi-Fi kutoka kwenye Mipangilio."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Jisajili na mtoa huduma wako"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Upigaji Simu kwa Wi-Fi"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ta/strings.xml b/core/res/res/values-mcc310-mnc260-ta/strings.xml deleted file mode 100644 index 144bc95ad766..000000000000 --- a/core/res/res/values-mcc310-mnc260-ta/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"வைஃபை மூலம் அழைக்க மற்றும் செய்திகள் அனுப்ப, முதலில் மொபைல் நிறுவனத்திடம் இந்தச் சேவையை அமைக்குமாறு கேட்கவும். பிறகு அமைப்புகளில் மீண்டும் வைஃபை அழைப்பை இயக்கவும்."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"உங்கள் மொபைல் நிறுவனத்தில் பதிவுசெய்யவும்"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s வைஃபை அழைப்பு"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-te/strings.xml b/core/res/res/values-mcc310-mnc260-te/strings.xml deleted file mode 100644 index ef94c4c047e5..000000000000 --- a/core/res/res/values-mcc310-mnc260-te/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fiలో కాల్లు చేయడం మరియు సందేశాలు పంపడం కోసం ముందుగా ఈ సేవను సెటప్ చేయడానికి మీ క్యారియర్ను అడగండి. ఆపై సెట్టింగ్ల నుండి మళ్లీ Wi-Fi కాలింగ్ను ఆన్ చేయండి."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"మీ క్యారియర్తో నమోదు చేయండి"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi కాలింగ్"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-th/strings.xml b/core/res/res/values-mcc310-mnc260-th/strings.xml deleted file mode 100644 index dd026ccd1e30..000000000000 --- a/core/res/res/values-mcc310-mnc260-th/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"หากต้องการโทรออกและส่งข้อความผ่าน Wi-Fi โปรดสอบถามผู้ให้บริการของคุณก่อนเพื่อตั้งค่าบริการนี้ แล้วเปิดการโทรผ่าน Wi-Fi อีกครั้งจากการตั้งค่า"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"ลงทะเบียนกับผู้ให้บริการ"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"กำลังเรียก Wi-Fi ของ %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-tl/strings.xml b/core/res/res/values-mcc310-mnc260-tl/strings.xml deleted file mode 100644 index 555783597984..000000000000 --- a/core/res/res/values-mcc310-mnc260-tl/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Upang tumawag at magpadala ng mga mensahe sa pamamagitan ng Wi-Fi, hilingin muna sa iyong carrier na i-set up ang serbisyong ito. Pagkatapos ay muling i-on ang pagtawag sa Wi-Fi mula sa Mga Setting."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Magparehistro sa iyong carrier"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Pagtawag sa Pamamagitan ng Wi-Fi ng %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-tr/strings.xml b/core/res/res/values-mcc310-mnc260-tr/strings.xml deleted file mode 100644 index 7cfd9c145bfd..000000000000 --- a/core/res/res/values-mcc310-mnc260-tr/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Kablosuz ağ üzerinden telefon etmek ve ileti göndermek için ilk önce operatörünüzden bu hizmeti ayarlamasını isteyin. Sonra tekrar Ayarlar\'dan Kablosuz çağrı özelliğini açın."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Operatörünüze kaydolun"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Kablosuz Çağrı"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-uk/strings.xml b/core/res/res/values-mcc310-mnc260-uk/strings.xml deleted file mode 100644 index 0c21309d4f38..000000000000 --- a/core/res/res/values-mcc310-mnc260-uk/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Щоб телефонувати або надсилати повідомлення через Wi-Fi, спочатку попросіть свого оператора налаштувати цю послугу. Після цього ввімкніть дзвінки через Wi-Fi у налаштуваннях."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Зареєструйтеся в оператора"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Дзвінок через Wi-Fi від оператора %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-ur/strings.xml b/core/res/res/values-mcc310-mnc260-ur/strings.xml deleted file mode 100644 index 5e93fa793998..000000000000 --- a/core/res/res/values-mcc310-mnc260-ur/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi سے کالز کرنے اور پیغامات بھیجنے کیلئے، پہلے اپنے کیریئر سے اس سروس کو ترتیب دینے کیلئے کہیں۔ پھر ترتیبات سے دوبارہ Wi-Fi کالنگ آن کریں۔"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"اپنے کیریئر کے ساتھ رجسٹر کریں"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi کالنگ"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-uz/strings.xml b/core/res/res/values-mcc310-mnc260-uz/strings.xml deleted file mode 100644 index 19c8f2e3f6e0..000000000000 --- a/core/res/res/values-mcc310-mnc260-uz/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Wi-Fi orqali qo‘ng‘iroqlarni amalga oshirish va xabarlar bilan almashinish uchun uyali aloqa operatoringizdan ushbu xizmatni yoqib qo‘yishni so‘rashingiz lozim. Keyin sozlamalarda Wi-Fi qo‘ng‘irog‘i imkoniyatini yoqib olishingiz mumkin."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Mobil operatoringiz yordamida ro‘yxatdan o‘ting"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi qo‘ng‘iroqlar"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-vi/strings.xml b/core/res/res/values-mcc310-mnc260-vi/strings.xml deleted file mode 100644 index 7b249c8da102..000000000000 --- a/core/res/res/values-mcc310-mnc260-vi/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Để gọi điện và gửi tin nhắn qua Wi-Fi, trước tiên hãy yêu cầu nhà cung cấp dịch vụ của bạn thiết lập dịch vụ này. Sau đó, bật lại gọi qua Wi-Fi từ Cài đặt."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Đăng ký với nhà cung cấp dịch vụ của bạn"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"Gọi điện qua Wi-Fi %s"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml deleted file mode 100644 index 7624e91ca194..000000000000 --- a/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"要通过 WLAN 打电话和发信息,请先让您的运营商开通此服务,然后再到“设置”中重新开启 WLAN 通话功能。"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"向您的运营商注册"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WLAN 通话功能"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml deleted file mode 100644 index 1aea15a13e00..000000000000 --- a/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"如要透過 Wi-Fi 撥打電話及傳送訊息,請先向您的流動網絡供應商要求設定此服務。然後再次在「設定」中開啟 Wi-Fi 通話。"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"向您的流動網絡供應商註冊"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 通話"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml deleted file mode 100644 index b0c7834fa592..000000000000 --- a/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"如要透過 Wi-FI 撥打電話及傳送訊息,請先要求您的行動通訊業者開通這項服務,然後再到「設定」啟用 Wi-Fi 通話功能。"</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"向您的行動通訊業者註冊"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 通話"</string> -</resources> diff --git a/core/res/res/values-mcc310-mnc260-zu/strings.xml b/core/res/res/values-mcc310-mnc260-zu/strings.xml deleted file mode 100644 index cc32b1eca64a..000000000000 --- a/core/res/res/values-mcc310-mnc260-zu/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/* -** Copyright 2015, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You my obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - --> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="7239039348648848288">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-FI, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-FI futhi kusukela kuzilungiselelo."</item> - </string-array> - <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="483847327467331298">"Bhalisa ngenkampani yakho yenethiwekhi"</item> - </string-array> - <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ukushaya kwe-Wi-Fi"</string> -</resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 46dbf046d12b..40380100121a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1673,6 +1673,10 @@ The size of the WAL file is also constrained by 'db_journal_size_limit'. --> <integer name="db_wal_autocheckpoint">100</integer> + <!-- The number of milliseconds that SQLite connection is allowed to be idle before it + is closed and removed from the pool --> + <integer name="db_default_idle_connection_timeout">30000</integer> + <!-- Max space (in MB) allocated to DownloadManager to store the downloaded files if they are to be stored in DownloadManager's data dir, which typically is /data/data/com.android.providers.downloads/files --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4b3440242817..a8aa35f1d40c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -218,7 +218,7 @@ </string-array> <!-- WFC Operator Error Messages showed as notifications --> <string-array name="wfcOperatorErrorNotificationMessages"> - <item>Register with your carrier</item> + <item>Register with your carrier (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item> </string-array> <!-- Template for showing mobile network operator name while WFC is active --> <string-array name="wfcSpnFormats"> @@ -3131,9 +3131,9 @@ <!-- See USB_PREFERENCES. This is the message. --> <string name="usb_notification_message">Tap for more options.</string> <!-- USB_PREFERENCES: Notification for when a type-c USB audio accessory is attached but not supported. This is the title --> - <string name="usb_unsupported_audio_accessory_title">Audio accessory not supported</string> + <string name="usb_unsupported_audio_accessory_title">Analog audio accessory detected</string> <!-- Message of notification shown when a type-c USB audio accessory is attached but not supported. --> - <string name="usb_unsupported_audio_accessory_message">Tap for more info</string> + <string name="usb_unsupported_audio_accessory_message">The attached device is not compatible with this phone. Tap to learn more.</string> <!-- Title of notification shown when ADB is actively connected to the phone. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 37f1daa2193b..f392ea0e3833 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -428,6 +428,7 @@ <java-symbol type="integer" name="db_connection_pool_size" /> <java-symbol type="integer" name="db_journal_size_limit" /> <java-symbol type="integer" name="db_wal_autocheckpoint" /> + <java-symbol type="integer" name="db_default_idle_connection_timeout" /> <java-symbol type="integer" name="config_soundEffectVolumeDb" /> <java-symbol type="integer" name="config_lockSoundVolumeDb" /> <java-symbol type="integer" name="config_multiuserMaximumUsers" /> diff --git a/core/tests/coretests/assets/fonts/a3em.ttf b/core/tests/coretests/assets/fonts/a3em.ttf Binary files differdeleted file mode 100644 index a601ce2ed932..000000000000 --- a/core/tests/coretests/assets/fonts/a3em.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/a3em.ttx b/core/tests/coretests/assets/fonts/a3em.ttx deleted file mode 100644 index d3b9e1603764..000000000000 --- a/core/tests/coretests/assets/fonts/a3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="1em"/> - <GlyphID id="2" name="3em"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="1em" width="1000" lsb="93"/> - <mtx name="3em" width="3000" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_4 platformID="3" platEncID="10" language="0"> - <map code="0x0061" name="3em" /> - <map code="0x0062" name="1em" /> - <map code="0x0063" name="1em" /> - <map code="0x0064" name="1em" /> - <map code="0x0065" name="1em" /> - </cmap_format_4> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/assets/fonts/all2em.ttf b/core/tests/coretests/assets/fonts/all2em.ttf Binary files differdeleted file mode 100644 index 482f7552f510..000000000000 --- a/core/tests/coretests/assets/fonts/all2em.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/all2em.ttx b/core/tests/coretests/assets/fonts/all2em.ttx deleted file mode 100644 index fe95ff04d1e3..000000000000 --- a/core/tests/coretests/assets/fonts/all2em.ttx +++ /dev/null @@ -1,184 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="2em"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="2em" width="1000" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_4 platformID="3" platEncID="10" language="0"> - <map code="0x0061" name="2em" /> - <map code="0x0062" name="2em" /> - <map code="0x0063" name="2em" /> - <map code="0x0064" name="2em" /> - <map code="0x0065" name="2em" /> - </cmap_format_4> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="2em" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/assets/fonts/b3em.ttf b/core/tests/coretests/assets/fonts/b3em.ttf Binary files differdeleted file mode 100644 index 63948a22c113..000000000000 --- a/core/tests/coretests/assets/fonts/b3em.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/b3em.ttx b/core/tests/coretests/assets/fonts/b3em.ttx deleted file mode 100644 index b5a77ef09bd3..000000000000 --- a/core/tests/coretests/assets/fonts/b3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="1em"/> - <GlyphID id="2" name="3em"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="1em" width="1000" lsb="93"/> - <mtx name="3em" width="3000" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_4 platformID="3" platEncID="10" language="0"> - <map code="0x0061" name="1em" /> - <map code="0x0062" name="3em" /> - <map code="0x0063" name="1em" /> - <map code="0x0064" name="1em" /> - <map code="0x0065" name="1em" /> - </cmap_format_4> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/assets/fonts/c3em.ttf b/core/tests/coretests/assets/fonts/c3em.ttf Binary files differdeleted file mode 100644 index badc3e29868f..000000000000 --- a/core/tests/coretests/assets/fonts/c3em.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/c3em.ttx b/core/tests/coretests/assets/fonts/c3em.ttx deleted file mode 100644 index f5ed8e556332..000000000000 --- a/core/tests/coretests/assets/fonts/c3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="1em"/> - <GlyphID id="2" name="3em"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="1em" width="1000" lsb="93"/> - <mtx name="3em" width="3000" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_4 platformID="3" platEncID="10" language="0"> - <map code="0x0061" name="1em" /> - <map code="0x0062" name="1em" /> - <map code="0x0063" name="3em" /> - <map code="0x0064" name="1em" /> - <map code="0x0065" name="1em" /> - </cmap_format_4> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/assets/fonts/no_coverage.ttf b/core/tests/coretests/assets/fonts/no_coverage.ttf Binary files differdeleted file mode 100644 index c884881c5026..000000000000 --- a/core/tests/coretests/assets/fonts/no_coverage.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/no_coverage.ttx b/core/tests/coretests/assets/fonts/no_coverage.ttx deleted file mode 100644 index 3be5f8626bf1..000000000000 --- a/core/tests/coretests/assets/fonts/no_coverage.ttx +++ /dev/null @@ -1,180 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="dummy"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="1000"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="1.0"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="500" lsb="93"/> - <mtx name="dummy" width="500" lsb="93"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_4 platformID="3" platEncID="10" language="0"> - <map code="0xFFFD" name="dummy" /> <!-- dummy entry --> - </cmap_format_4> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="dummy" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> - Copyright (C) 2017 The Android Open Source Project - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - <namerecord nameID="13" platformID="3" platEncID="1" langID="0x409"> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - </namerecord> - <namerecord nameID="14" platformID="3" platEncID="1" langID="0x409"> - http://www.apache.org/licenses/LICENSE-2.0 - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java index 7800f4ab0598..f97d51d3a38a 100644 --- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java +++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java @@ -25,6 +25,8 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; import android.database.sqlite.SQLiteException; import android.os.Parcel; +import android.support.test.InstrumentationRegistry; +import android.support.test.uiautomator.UiDevice; import android.test.AndroidTestCase; import android.test.PerformanceTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -1185,4 +1187,38 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT fail("unexpected"); } } + + @MediumTest + public void testCloseIdleConnection() throws Exception { + mDatabase.close(); + SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder() + .setIdleConnectionTimeout(1000).build(); + mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), params); + // Wait a bit and check that connection is still open + Thread.sleep(100); + String output = executeShellCommand("dumpsys dbinfo " + getContext().getPackageName()); + assertTrue("Connection #0 should be open. Output: " + output, + output.contains("Connection #0:")); + + // Now cause idle timeout and check that connection is closed + Thread.sleep(1000); + output = executeShellCommand("dumpsys dbinfo " + getContext().getPackageName()); + assertFalse("Connection #0 should be closed. Output: " + output, + output.contains("Connection #0:")); + } + + @SmallTest + public void testSetIdleConnectionTimeoutValidation() throws Exception { + try { + new SQLiteDatabase.OpenParams.Builder().setIdleConnectionTimeout(-1).build(); + fail("Negative timeout should be rejected"); + } catch (IllegalArgumentException expected) { + } + } + + private String executeShellCommand(String cmd) throws Exception { + return UiDevice.getInstance( + InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd); + } + } diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java deleted file mode 100644 index ca4f7d43caf4..000000000000 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ /dev/null @@ -1,469 +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.graphics; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.content.Context; -import android.content.res.AssetManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.util.ArrayMap; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class TypefaceSystemFallbackTest { - private static final String SYSTEM_FONT_DIR = "/system/fonts/"; - private static final String SYSTEM_FONTS_XML = "/system/etc/fonts.xml"; - - private static final String[] TEST_FONT_FILES = { - "a3em.ttf", // Supports "a","b","c". The width of "a" is 3em, others are 1em. - "b3em.ttf", // Supports "a","b","c". The width of "b" is 3em, others are 1em. - "c3em.ttf", // Supports "a","b","c". The width of "c" is 3em, others are 1em. - "all2em.ttf", // Supports "a,","b","c". All of them have the same width of 2em. - "no_coverage.ttf", // This font doesn't support any characters. - }; - private static final String TEST_FONTS_XML; - private static final String TEST_FONT_DIR; - - private static final float GLYPH_1EM_WIDTH; - private static final float GLYPH_2EM_WIDTH; - private static final float GLYPH_3EM_WIDTH; - - static { - final Context targetCtx = InstrumentationRegistry.getInstrumentation().getTargetContext(); - final File cacheDir = new File(targetCtx.getCacheDir(), "TypefaceSystemFallbackTest"); - if (!cacheDir.isDirectory()) { - cacheDir.mkdirs(); - } - TEST_FONT_DIR = cacheDir.getAbsolutePath() + "/"; - TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath(); - - final AssetManager am = - InstrumentationRegistry.getInstrumentation().getContext().getAssets(); - final Paint paint = new Paint(); - paint.setTypeface(new Typeface.Builder(am, "fonts/a3em.ttf").build()); - GLYPH_3EM_WIDTH = paint.measureText("a"); - GLYPH_1EM_WIDTH = paint.measureText("b"); - - paint.setTypeface(new Typeface.Builder(am, "fonts/all2em.ttf").build()); - GLYPH_2EM_WIDTH = paint.measureText("a"); - } - - @Before - public void setUp() { - final AssetManager am = - InstrumentationRegistry.getInstrumentation().getContext().getAssets(); - for (final String fontFile : TEST_FONT_FILES) { - final String sourceInAsset = "fonts/" + fontFile; - final File outInCache = new File(TEST_FONT_DIR, fontFile); - try (InputStream is = am.open(sourceInAsset)) { - Files.copy(is, outInCache.toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @After - public void tearDown() { - for (final String fontFile : TEST_FONT_FILES) { - final File outInCache = new File(TEST_FONT_DIR, fontFile); - outInCache.delete(); - } - } - - private static void buildSystemFallback(String xml, - ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { - try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) { - fos.write(xml.getBytes(Charset.forName("UTF-8"))); - } catch (IOException e) { - throw new RuntimeException(e); - } - Typeface.buildSystemFallback(TEST_FONTS_XML, TEST_FONT_DIR, fontMap, fallbackMap); - } - - @Test - public void testBuildSystemFallback() { - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - Typeface.buildSystemFallback(SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, fontMap, fallbackMap); - - assertFalse(fontMap.isEmpty()); - assertFalse(fallbackMap.isEmpty()); - } - - @Test - public void testBuildSystemFallback_NonExistentFontShouldBeIgnored() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " <font weight='400' style='normal'>NoSuchFont.ttf</font>" - + " </family>" - + " <family name='NoSuchFont'>" - + " <font weight='400' style='normal'>NoSuchFont.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>NoSuchFont.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - assertEquals(1, fontMap.size()); - assertTrue(fontMap.containsKey("sans-serif")); - assertEquals(1, fallbackMap.size()); - assertTrue(fallbackMap.containsKey("sans-serif")); - } - - @Test - public void testBuildSystemFallback_NamedFamily() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " </family>" - + " <family name='test'>" - + " <font weight='400' style='normal'>b3em.ttf</font>" - + " </family>" - + " <family name='test2'>" - + " <font weight='400' style='normal'>c3em.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>all2em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface sansSerifTypeface = fontMap.get("sans-serif"); - assertNotNull(sansSerifTypeface); - paint.setTypeface(sansSerifTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface testTypeface = fontMap.get("test"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface test2Typeface = fontMap.get("test2"); - assertNotNull(test2Typeface); - paint.setTypeface(test2Typeface); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_defaultFallback() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>all2em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface sansSerifTypeface = fontMap.get("sans-serif"); - assertNotNull(sansSerifTypeface); - paint.setTypeface(sansSerifTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface testTypeface = fontMap.get("test"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_namedFallbackFamily() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test2'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal' fallbackFor='test2'>b3em.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>all2em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface sansSerifTypeface = fontMap.get("sans-serif"); - assertNotNull(sansSerifTypeface); - paint.setTypeface(sansSerifTypeface); - assertEquals(GLYPH_2EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface testTypeface = fontMap.get("test"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface test2Typeface = fontMap.get("test2"); - assertNotNull(test2Typeface); - paint.setTypeface(test2Typeface); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_namedFallbackFamily2() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test2'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>" - + " <font weight='400' style='normal'>b3em.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>all2em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface sansSerifTypeface = fontMap.get("sans-serif"); - assertNotNull(sansSerifTypeface); - paint.setTypeface(sansSerifTypeface); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface testTypeface = fontMap.get("test"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface test2Typeface = fontMap.get("test2"); - assertNotNull(test2Typeface); - paint.setTypeface(test2Typeface); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_ImplicitSansSerifFallback() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " </family>" - + " <family name='test'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='test2'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family>" - + " <font weight='400' style='normal'>all2em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface testTypeface = fontMap.get("test"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - final Typeface test2Typeface = fontMap.get("test2"); - assertNotNull(test2Typeface); - paint.setTypeface(test2Typeface); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_ElegantFallback() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family variant='elegant'>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " </family>" - + " <family variant='compact'>" - + " <font weight='400' style='normal'>b3em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - final Typeface testTypeface = fontMap.get("serif"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - paint.setElegantTextHeight(true); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - } - - @Test - public void testBuildSystemFallback_ElegantFallback_customFallback() { - final String xml = "<?xml version='1.0' encoding='UTF-8'?>" - + "<familyset version='22'>" - + " <family name='sans-serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family name='serif'>" - + " <font weight='400' style='normal'>no_coverage.ttf</font>" - + " </family>" - + " <family variant='elegant'>" - + " <font weight='400' style='normal'>a3em.ttf</font>" - + " <font weight='400' style='normal' fallbackFor='serif'>b3em.ttf</font>" - + " </family>" - + " <family variant='compact'>" - + " <font weight='400' style='normal'>c3em.ttf</font>" - + " </family>" - + "</familyset>"; - final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, fontMap, fallbackMap); - - final Paint paint = new Paint(); - - Typeface testTypeface = fontMap.get("serif"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - paint.setElegantTextHeight(true); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); - - testTypeface = fontMap.get("sans-serif"); - assertNotNull(testTypeface); - paint.setTypeface(testTypeface); - paint.setElegantTextHeight(true); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f); - - paint.setElegantTextHeight(false); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f); - assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f); - assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f); - } -} diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 80a9324d04f3..7c07a302dfe9 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -111,7 +111,6 @@ public class FontListParser { String weightStr = parser.getAttributeValue(null, "weight"); int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style")); - String fallbackFor = parser.getAttributeValue(null, "fallbackFor"); StringBuilder filename = new StringBuilder(); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() == XmlPullParser.TEXT) { @@ -127,7 +126,7 @@ public class FontListParser { } String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); return new FontConfig.Font(sanitizedName, index, - axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor); + axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic); } private static FontVariationAxis readAxis(XmlPullParser parser) diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 1d8b5830aa92..c4b56c333c64 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -38,7 +38,6 @@ import android.os.ResultReceiver; import android.provider.FontRequest; import android.provider.FontsContract; import android.text.FontConfig; -import android.util.ArrayMap; import android.util.Base64; import android.util.Log; import android.util.LongSparseArray; @@ -46,7 +45,6 @@ import android.util.LruCache; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import libcore.io.IoUtils; @@ -107,10 +105,12 @@ public class Typeface { private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16); static Typeface sDefaultTypeface; - static final Map<String, Typeface> sSystemFontMap; - static final Map<String, FontFamily[]> sSystemFallbackMap; + static Map<String, Typeface> sSystemFontMap; + static FontFamily[] sFallbackFonts; private static final Object sLock = new Object(); + static final String FONTS_CONFIG = "fonts.xml"; + /** * @hide */ @@ -129,7 +129,6 @@ public class Typeface { // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp /** @hide */ public static final int RESOLVE_BY_FONT_TABLE = -1; - private static final String DEFAULT_FAMILY = "sans-serif"; // Style value for building typeface. private static final int STYLE_NORMAL = 0; @@ -164,27 +163,28 @@ public class Typeface { */ @Nullable public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { - synchronized (sDynamicTypefaceCache) { - final String key = Builder.createAssetUid( - mgr, path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, - DEFAULT_FAMILY); - Typeface typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; - - FontFamily fontFamily = new FontFamily(); - // TODO: introduce ttc index and variation settings to resource type font. - if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, - 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, - RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { - if (!fontFamily.freeze()) { - return null; + if (sFallbackFonts != null) { + synchronized (sDynamicTypefaceCache) { + final String key = Builder.createAssetUid( + mgr, path, 0 /* ttcIndex */, null /* axes */, + RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); + Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; + + FontFamily fontFamily = new FontFamily(); + // TODO: introduce ttc index and variation settings to resource type font. + if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, + 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, + RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { + if (!fontFamily.freeze()) { + return null; + } + FontFamily[] families = {fontFamily}; + typeface = createFromFamiliesWithDefault(families, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + sDynamicTypefaceCache.put(key, typeface); + return typeface; } - FontFamily[] families = {fontFamily}; - typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - sDynamicTypefaceCache.put(key, typeface); - return typeface; } } return null; @@ -197,57 +197,61 @@ public class Typeface { @Nullable public static Typeface createFromResources( FamilyResourceEntry entry, AssetManager mgr, String path) { - if (entry instanceof ProviderResourceEntry) { - final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; - // Downloadable font - List<List<String>> givenCerts = providerEntry.getCerts(); - List<List<byte[]>> certs = new ArrayList<>(); - if (givenCerts != null) { - for (int i = 0; i < givenCerts.size(); i++) { - List<String> certSet = givenCerts.get(i); - List<byte[]> byteArraySet = new ArrayList<>(); - for (int j = 0; j < certSet.size(); j++) { - byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT)); + if (sFallbackFonts != null) { + if (entry instanceof ProviderResourceEntry) { + final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; + // Downloadable font + List<List<String>> givenCerts = providerEntry.getCerts(); + List<List<byte[]>> certs = new ArrayList<>(); + if (givenCerts != null) { + for (int i = 0; i < givenCerts.size(); i++) { + List<String> certSet = givenCerts.get(i); + List<byte[]> byteArraySet = new ArrayList<>(); + for (int j = 0; j < certSet.size(); j++) { + byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT)); + } + certs.add(byteArraySet); } - certs.add(byteArraySet); } + // Downloaded font and it wasn't cached, request it again and return a + // default font instead (nothing we can do now). + FontRequest request = new FontRequest(providerEntry.getAuthority(), + providerEntry.getPackage(), providerEntry.getQuery(), certs); + Typeface typeface = FontsContract.getFontSync(request); + return typeface == null ? DEFAULT : typeface; } - // Downloaded font and it wasn't cached, request it again and return a - // default font instead (nothing we can do now). - FontRequest request = new FontRequest(providerEntry.getAuthority(), - providerEntry.getPackage(), providerEntry.getQuery(), certs); - Typeface typeface = FontsContract.getFontSync(request); - return typeface == null ? DEFAULT : typeface; - } - Typeface typeface = findFromCache(mgr, path); - if (typeface != null) return typeface; + Typeface typeface = findFromCache(mgr, path); + if (typeface != null) return typeface; - // family is FontFamilyFilesResourceEntry - final FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) entry; + // family is FontFamilyFilesResourceEntry + final FontFamilyFilesResourceEntry filesEntry = + (FontFamilyFilesResourceEntry) entry; - FontFamily fontFamily = new FontFamily(); - for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { - // TODO: Add ttc and variation font support. (b/37853920) - if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), - 0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */, - fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) { + FontFamily fontFamily = new FontFamily(); + for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { + // TODO: Add ttc and variation font support. (b/37853920) + if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), + 0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */, + fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) { + return null; + } + } + if (!fontFamily.freeze()) { return null; } + FontFamily[] familyChain = { fontFamily }; + typeface = createFromFamiliesWithDefault(familyChain, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + synchronized (sDynamicTypefaceCache) { + final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, + null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, + RESOLVE_BY_FONT_TABLE /* italic */); + sDynamicTypefaceCache.put(key, typeface); + } + return typeface; } - if (!fontFamily.freeze()) { - return null; - } - FontFamily[] familyChain = { fontFamily }; - typeface = createFromFamiliesWithDefault(familyChain, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - synchronized (sDynamicTypefaceCache) { - final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, - null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, - RESOLVE_BY_FONT_TABLE /* italic */, DEFAULT_FAMILY); - sDynamicTypefaceCache.put(key, typeface); - } - return typeface; + return null; } /** @@ -257,8 +261,7 @@ public class Typeface { public static Typeface findFromCache(AssetManager mgr, String path) { synchronized (sDynamicTypefaceCache) { final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, - DEFAULT_FAMILY); + RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); Typeface typeface = sDynamicTypefaceCache.get(key); if (typeface != null) { return typeface; @@ -495,7 +498,7 @@ public class Typeface { * @return Unique id for a given AssetManager and asset path. */ private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex, - @Nullable FontVariationAxis[] axes, int weight, int italic, String fallback) { + @Nullable FontVariationAxis[] axes, int weight, int italic) { final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers(); final StringBuilder builder = new StringBuilder(); final int size = pkgs.size(); @@ -510,11 +513,7 @@ public class Typeface { builder.append(Integer.toString(weight)); builder.append("-"); builder.append(Integer.toString(italic)); - // Family name may contain hyphen. Use double hyphen for avoiding key conflicts before - // and after appending falblack name. - builder.append("--"); - builder.append(fallback); - builder.append("--"); + builder.append("-"); if (axes != null) { for (FontVariationAxis axis : axes) { builder.append(axis.getTag()); @@ -594,15 +593,13 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } catch (IOException e) { return resolveFallbackTypeface(); } } else if (mAssetManager != null) { // Builder is created with asset manager. final String key = createAssetUid( - mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic, - mFallbackFamilyName); + mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic); synchronized (sLock) { Typeface typeface = sDynamicTypefaceCache.get(key); if (typeface != null) return typeface; @@ -616,8 +613,7 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - typeface = createFromFamiliesWithDefault(families, mFallbackFamilyName, - mWeight, mItalic); + typeface = createFromFamiliesWithDefault(families, mWeight, mItalic); sDynamicTypefaceCache.put(key, typeface); return typeface; } @@ -631,8 +627,7 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } else if (mFonts != null) { final FontFamily fontFamily = new FontFamily(); boolean atLeastOneFont = false; @@ -658,8 +653,7 @@ public class Typeface { } fontFamily.freeze(); FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } // Must not reach here. @@ -679,7 +673,10 @@ public class Typeface { * @return The best matching typeface. */ public static Typeface create(String familyName, int style) { - return create(sSystemFontMap.get(familyName), style); + if (sSystemFontMap != null) { + return create(sSystemFontMap.get(familyName), style); + } + return null; } /** @@ -754,33 +751,34 @@ public class Typeface { if (path == null) { throw new NullPointerException(); // for backward compatibility } - synchronized (sLock) { - Typeface typeface = new Builder(mgr, path).build(); - if (typeface != null) return typeface; + if (sFallbackFonts != null) { + synchronized (sLock) { + Typeface typeface = new Builder(mgr, path).build(); + if (typeface != null) return typeface; - final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, - null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, - DEFAULT_FAMILY); - typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; + final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, + null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; - final FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, - 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, - null /* axes */)) { - // Due to backward compatibility, even if the font is not supported by our font - // stack, we need to place the empty font at the first place. The typeface with - // empty font behaves different from default typeface especially in fallback - // font selection. - fontFamily.allowUnsupportedFont(); - fontFamily.freeze(); - final FontFamily[] families = { fontFamily }; - typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - sDynamicTypefaceCache.put(key, typeface); - return typeface; - } else { - fontFamily.abortCreation(); + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, + 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, + null /* axes */)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback + // font selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + final FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } else { + fontFamily.abortCreation(); + } } } throw new RuntimeException("Font asset not found " + path); @@ -817,20 +815,22 @@ public class Typeface { * @return The new typeface. */ public static Typeface createFromFile(@Nullable String path) { - final FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { - // Due to backward compatibility, even if the font is not supported by our font - // stack, we need to place the empty font at the first place. The typeface with - // empty font behaves different from default typeface especially in fallback font - // selection. - fontFamily.allowUnsupportedFont(); - fontFamily.freeze(); - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - } else { - fontFamily.abortCreation(); + if (sFallbackFonts != null) { + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback font + // selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + FontFamily[] families = { fontFamily }; + return createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE); + } else { + fontFamily.abortCreation(); + } } throw new RuntimeException("Font not found " + path); } @@ -852,8 +852,6 @@ public class Typeface { /** * Create a new typeface from an array of font families, including * also the font families in the fallback list. - * @param fallbackName the family name. If given families don't support characters, the - * characters will be rendered with this family. * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that * case, the table information in the first family's font is used. If the first * family has multiple fonts, the closest to the regular weight and upright font @@ -865,17 +863,13 @@ public class Typeface { * @param families array of font families */ private static Typeface createFromFamiliesWithDefault(FontFamily[] families, - String fallbackName, int weight, int italic) { - FontFamily[] fallback = sSystemFallbackMap.get(fallbackName); - if (fallback == null) { - fallback = sSystemFallbackMap.get(DEFAULT_FAMILY); - } - long[] ptrArray = new long[families.length + fallback.length]; + int weight, int italic) { + long[] ptrArray = new long[families.length + sFallbackFonts.length]; for (int i = 0; i < families.length; i++) { ptrArray[i] = families[i].mNativePtr; } - for (int i = 0; i < fallback.length; i++) { - ptrArray[i + families.length] = fallback[i].mNativePtr; + for (int i = 0; i < sFallbackFonts.length; i++) { + ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr; } return new Typeface(nativeCreateFromArray(ptrArray, weight, italic)); } @@ -891,189 +885,113 @@ public class Typeface { mWeight = nativeGetWeight(ni); } - private static @Nullable ByteBuffer mmap(String fullPath) { - try (FileInputStream file = new FileInputStream(fullPath)) { - final FileChannel fileChannel = file.getChannel(); - final long fontSize = fileChannel.size(); - return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); - } catch (IOException e) { - Log.e(TAG, "Error mapping font file " + fullPath); - return null; - } - } - - private static @Nullable FontFamily createFontFamily( - String familyName, List<FontConfig.Font> fonts, String languageTag, int variant, - Map<String, ByteBuffer> cache, String fontDir) { - final FontFamily family = new FontFamily(languageTag, variant); - for (int i = 0; i < fonts.size(); i++) { - final FontConfig.Font font = fonts.get(i); - final String fullPath = fontDir + font.getFontName(); - ByteBuffer buffer = cache.get(fullPath); - if (buffer == null) { - if (cache.containsKey(fullPath)) { - continue; // Already failed to mmap. Skip it. - } - buffer = mmap(fullPath); - cache.put(fullPath, buffer); - if (buffer == null) { + private static FontFamily makeFamilyFromParsed(FontConfig.Family family, + Map<String, ByteBuffer> bufferForPath) { + FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant()); + for (FontConfig.Font font : family.getFonts()) { + String fullPathName = "/system/fonts/" + font.getFontName(); + ByteBuffer fontBuffer = bufferForPath.get(fullPathName); + if (fontBuffer == null) { + try (FileInputStream file = new FileInputStream(fullPathName)) { + FileChannel fileChannel = file.getChannel(); + long fontSize = fileChannel.size(); + fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); + bufferForPath.put(fullPathName, fontBuffer); + } catch (IOException e) { + Log.e(TAG, "Error mapping font file " + fullPathName); continue; } } - if (!family.addFontFromBuffer(buffer, font.getTtcIndex(), font.getAxes(), + if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(), font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) { - Log.e(TAG, "Error creating font " + fullPath + "#" + font.getTtcIndex()); + Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex()); } } - if (!family.freeze()) { - Log.e(TAG, "Unable to load Family: " + familyName + " : " + languageTag); + if (!fontFamily.freeze()) { + // Treat as system error since reaching here means that a system pre-installed font + // can't be used by our font stack. + Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage()); return null; } - return family; + return fontFamily; } - private static void pushFamilyToFallback(FontConfig.Family xmlFamily, - ArrayMap<String, ArrayList<FontFamily>> fallbackMap, - Map<String, ByteBuffer> cache, - String fontDir) { - - final String languageTag = xmlFamily.getLanguage(); - final int variant = xmlFamily.getVariant(); - - final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>(); - final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>(); - - // Collect default fallback and specific fallback fonts. - for (final FontConfig.Font font : xmlFamily.getFonts()) { - final String fallbackName = font.getFallbackFor(); - if (fallbackName == null) { - defaultFonts.add(font); - } else { - ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(fallbackName); - if (fallback == null) { - fallback = new ArrayList<>(); - specificFallbackFonts.put(fallbackName, fallback); - } - fallback.add(font); - } - } - - final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( - xmlFamily.getName(), defaultFonts, languageTag, variant, cache, fontDir); - - // Insert family into fallback map. - for (int i = 0; i < fallbackMap.size(); i++) { - final ArrayList<FontConfig.Font> fallback = - specificFallbackFonts.get(fallbackMap.keyAt(i)); - if (fallback == null) { - if (defaultFamily != null) { - fallbackMap.valueAt(i).add(defaultFamily); - } - } else { - final FontFamily family = createFontFamily( - xmlFamily.getName(), fallback, languageTag, variant, cache, fontDir); - if (family != null) { - fallbackMap.valueAt(i).add(family); - } - } - } - } - - /** - * Build the system fallback from xml file. + /* + * (non-Javadoc) * - * @param xmlPath A full path string to the fonts.xml file. - * @param fontDir A full path string to the system font directory. This must end with - * slash('/'). - * @param fontMap An output system font map. Caller must pass empty map. - * @param fallbackMap An output system fallback map. Caller must pass empty map. - * @hide + * This should only be called once, from the static class initializer block. */ - @VisibleForTesting - public static void buildSystemFallback(String xmlPath, String fontDir, - ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { + private static void init() { + // Load font config and initialize Minikin state + File systemFontConfigLocation = getSystemFontConfigLocation(); + File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG); try { - final FileInputStream fontsIn = new FileInputStream(xmlPath); - final FontConfig fontConfig = FontListParser.parse(fontsIn); - - final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>(); - final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies(); - - final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>(); - // First traverse families which have a 'name' attribute to create fallback map. - for (final FontConfig.Family xmlFamily : xmlFamilies) { - final String familyName = xmlFamily.getName(); - if (familyName == null) { - continue; - } - final FontFamily family = createFontFamily( - xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()), - xmlFamily.getLanguage(), xmlFamily.getVariant(), bufferCache, fontDir); - if (family == null) { - continue; - } - final ArrayList<FontFamily> fallback = new ArrayList<>(); - fallback.add(family); - fallbackListMap.put(familyName, fallback); - } - - // Then, add fallback fonts to the each fallback map. - for (int i = 0; i < xmlFamilies.length; i++) { - final FontConfig.Family xmlFamily = xmlFamilies[i]; - // The first family (usually the sans-serif family) is always placed immediately - // after the primary family in the fallback. - if (i == 0 || xmlFamily.getName() == null) { - pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir); + FileInputStream fontsIn = new FileInputStream(configFilename); + FontConfig fontConfig = FontListParser.parse(fontsIn); + + Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>(); + + List<FontFamily> familyList = new ArrayList<FontFamily>(); + // Note that the default typeface is always present in the fallback list; + // this is an enhancement from pre-Minikin behavior. + for (int i = 0; i < fontConfig.getFamilies().length; i++) { + FontConfig.Family f = fontConfig.getFamilies()[i]; + if (i == 0 || f.getName() == null) { + FontFamily family = makeFamilyFromParsed(f, bufferForPath); + if (family != null) { + familyList.add(family); + } } } - - // Build the font map and fallback map. - for (int i = 0; i < fallbackListMap.size(); i++) { - final String fallbackName = fallbackListMap.keyAt(i); - final List<FontFamily> familyList = fallbackListMap.valueAt(i); - final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]); - - fallbackMap.put(fallbackName, families); - final long[] ptrArray = new long[families.length]; - for (int j = 0; j < families.length; j++) { - ptrArray[j] = families[j].mNativePtr; + sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); + setDefault(Typeface.createFromFamilies(sFallbackFonts)); + + Map<String, Typeface> systemFonts = new HashMap<String, Typeface>(); + for (int i = 0; i < fontConfig.getFamilies().length; i++) { + Typeface typeface; + FontConfig.Family f = fontConfig.getFamilies()[i]; + if (f.getName() != null) { + if (i == 0) { + // The first entry is the default typeface; no sense in + // duplicating the corresponding FontFamily. + typeface = sDefaultTypeface; + } else { + FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath); + if (fontFamily == null) { + continue; + } + FontFamily[] families = { fontFamily }; + typeface = Typeface.createFromFamiliesWithDefault(families, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + } + systemFonts.put(f.getName(), typeface); } - fontMap.put(fallbackName, new Typeface(nativeCreateFromArray( - ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE))); } - - // Insert alias to font maps. - for (final FontConfig.Alias alias : fontConfig.getAliases()) { - Typeface base = fontMap.get(alias.getToName()); + for (FontConfig.Alias alias : fontConfig.getAliases()) { + Typeface base = systemFonts.get(alias.getToName()); Typeface newFace = base; int weight = alias.getWeight(); if (weight != 400) { newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); } - fontMap.put(alias.getName(), newFace); + systemFonts.put(alias.getName(), newFace); } + sSystemFontMap = systemFonts; + } catch (RuntimeException e) { Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e); // TODO: normal in non-Minikin case, remove or make error when Minikin-only } catch (FileNotFoundException e) { - Log.e(TAG, "Error opening " + xmlPath, e); + Log.e(TAG, "Error opening " + configFilename, e); } catch (IOException e) { - Log.e(TAG, "Error reading " + xmlPath, e); + Log.e(TAG, "Error reading " + configFilename, e); } catch (XmlPullParserException e) { - Log.e(TAG, "XML parse exception for " + xmlPath, e); + Log.e(TAG, "XML parse exception for " + configFilename, e); } } static { - final ArrayMap<String, Typeface> systemFontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>(); - buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", systemFontMap, - systemFallbackMap); - sSystemFontMap = Collections.unmodifiableMap(systemFontMap); - sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap); - - setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); - + init(); // Set up defaults and typefaces exposed in public API DEFAULT = create((String) null, 0); DEFAULT_BOLD = create((String) null, Typeface.BOLD); @@ -1090,6 +1008,10 @@ public class Typeface { } + private static File getSystemFontConfigLocation() { + return new File("/system/etc/"); + } + @Override protected void finalize() throws Throwable { try { diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index d96e376b0b70..f66bb045373c 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -68,7 +68,7 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style Typeface* gDefaultTypeface = NULL; Typeface* Typeface::resolveDefault(Typeface* src) { - LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr); + LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr); return src == nullptr ? gDefaultTypeface : src; } diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 30c1fff5e6ee..7e23ee152ed9 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -55,8 +55,6 @@ public class DeviceChooserActivity extends Activity { Log.e(LOG_TAG, "About to show UI, but no devices to show"); } - mPairButton = findViewById(R.id.button_pair); - if (getService().mRequest.isSingleDevice()) { setContentView(R.layout.device_confirmation); final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0); @@ -64,11 +62,13 @@ public class DeviceChooserActivity extends Activity { R.string.confirmation_title, getCallingAppName(), selectedDevice.getDisplayName()), 0)); + mPairButton = findViewById(R.id.button_pair); mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice)); getService().mSelectedDevice = selectedDevice; onSelectionUpdate(); } else { setContentView(R.layout.device_chooser); + mPairButton = findViewById(R.id.button_pair); mPairButton.setVisibility(View.GONE); setTitle(Html.fromHtml(getString(R.string.chooser_title, getCallingAppName()), 0)); mDeviceListView = findViewById(R.id.device_list); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index a814a9f938a6..d04ccf2665c1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -59,7 +59,9 @@ import com.android.settingslib.R; 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.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; @@ -120,6 +122,10 @@ public class AccessPoint implements Comparable<AccessPoint> { */ private final ConcurrentHashMap<String, ScanResult> mScanResultCache = new ConcurrentHashMap<String, ScanResult>(32); + + /** Map of BSSIDs to speed values for individual ScanResults. */ + private final Map<String, Integer> mScanResultScores = new HashMap<>(); + /** Maximum age of scan results to hold onto while actively scanning. **/ private static final long MAX_SCAN_RESULT_AGE_MS = 15000; @@ -280,6 +286,8 @@ public class AccessPoint implements Comparable<AccessPoint> { this.mNetworkInfo = that.mNetworkInfo; this.mScanResultCache.clear(); this.mScanResultCache.putAll(that.mScanResultCache); + this.mScanResultScores.clear(); + this.mScanResultScores.putAll(that.mScanResultScores); this.mId = that.mId; this.mSpeed = that.mSpeed; this.mIsScoredNetworkMetered = that.mIsScoredNetworkMetered; @@ -392,6 +400,7 @@ public class AccessPoint implements Comparable<AccessPoint> { */ boolean update(WifiNetworkScoreCache scoreCache, boolean scoringUiEnabled) { boolean scoreChanged = false; + mScanResultScores.clear(); if (scoringUiEnabled) { scoreChanged = updateScores(scoreCache); } @@ -407,6 +416,18 @@ public class AccessPoint implements Comparable<AccessPoint> { int oldSpeed = mSpeed; mSpeed = Speed.NONE; + for (ScanResult result : mScanResultCache.values()) { + ScoredNetwork score = scoreCache.getScoredNetwork(result); + if (score == null) { + continue; + } + + int speed = score.calculateBadge(result.level); + mScanResultScores.put(result.BSSID, speed); + mSpeed = Math.max(mSpeed, speed); + } + + // set mSpeed to the connected ScanResult if the AccessPoint is the active network if (isActive() && mInfo != null) { NetworkKey key = new NetworkKey(new WifiKey( AccessPoint.convertToQuotedString(ssid), mInfo.getBSSID())); @@ -414,15 +435,6 @@ public class AccessPoint implements Comparable<AccessPoint> { if (score != null) { mSpeed = score.calculateBadge(mInfo.getRssi()); } - } else { - for (ScanResult result : mScanResultCache.values()) { - ScoredNetwork score = scoreCache.getScoredNetwork(result); - if (score == null) { - continue; - } - // TODO(sghuman): Rename calculateBadge API - mSpeed = Math.max(mSpeed, score.calculateBadge(result.level)); - } } if(WifiTracker.sVerboseLogging) { @@ -813,8 +825,8 @@ public class AccessPoint implements Comparable<AccessPoint> { */ private String getVisibilityStatus() { StringBuilder visibility = new StringBuilder(); - StringBuilder scans24GHz = null; - StringBuilder scans5GHz = null; + StringBuilder scans24GHz = new StringBuilder(); + StringBuilder scans5GHz = new StringBuilder(); String bssid = null; long now = System.currentTimeMillis(); @@ -836,87 +848,55 @@ public class AccessPoint implements Comparable<AccessPoint> { visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate)); } - int rssi5 = WifiConfiguration.INVALID_RSSI; - int rssi24 = WifiConfiguration.INVALID_RSSI; - int num5 = 0; - int num24 = 0; + int maxRssi5 = WifiConfiguration.INVALID_RSSI; + int maxRssi24 = WifiConfiguration.INVALID_RSSI; + final int maxDisplayedScans = 4; + int num5 = 0; // number of scanned BSSID on 5GHz band + int num24 = 0; // number of scanned BSSID on 2.4Ghz band int numBlackListed = 0; - int n24 = 0; // Number scan results we included in the string - int n5 = 0; // Number scan results we included in the string evictOldScanResults(); + // TODO: sort list by RSSI or age for (ScanResult result : mScanResultCache.values()) { - if (result.frequency >= LOWER_FREQ_5GHZ && result.frequency <= HIGHER_FREQ_5GHZ) { // Strictly speaking: [4915, 5825] - // number of known BSSID on 5GHz band - num5 = num5 + 1; - } else if (result.frequency >= LOWER_FREQ_24GHZ - && result.frequency <= HIGHER_FREQ_24GHZ) { - // Strictly speaking: [2412, 2482] - // number of known BSSID on 2.4Ghz band - num24 = num24 + 1; - } - + num5++; - if (result.frequency >= LOWER_FREQ_5GHZ - && result.frequency <= HIGHER_FREQ_5GHZ) { - if (result.level > rssi5) { - rssi5 = result.level; + if (result.level > maxRssi5) { + maxRssi5 = result.level; } - if (n5 < 4) { - if (scans5GHz == null) scans5GHz = new StringBuilder(); - scans5GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*"); - scans5GHz.append("=").append(result.frequency); - scans5GHz.append(",").append(result.level); - scans5GHz.append("}"); - n5++; + if (num5 <= maxDisplayedScans) { + scans5GHz.append(verboseScanResultSummary(result, bssid)); } } else if (result.frequency >= LOWER_FREQ_24GHZ && result.frequency <= HIGHER_FREQ_24GHZ) { - if (result.level > rssi24) { - rssi24 = result.level; + // Strictly speaking: [2412, 2482] + num24++; + + if (result.level > maxRssi24) { + maxRssi24 = result.level; } - if (n24 < 4) { - if (scans24GHz == null) scans24GHz = new StringBuilder(); - scans24GHz.append(" \n{").append(result.BSSID); - if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*"); - scans24GHz.append("=").append(result.frequency); - scans24GHz.append(",").append(result.level); - scans24GHz.append("}"); - n24++; + if (num24 <= maxDisplayedScans) { + scans24GHz.append(verboseScanResultSummary(result, bssid)); } } } visibility.append(" ["); if (num24 > 0) { visibility.append("(").append(num24).append(")"); - if (n24 <= 4) { - if (scans24GHz != null) { - visibility.append(scans24GHz.toString()); - } - } else { - visibility.append("max=").append(rssi24); - if (scans24GHz != null) { - visibility.append(",").append(scans24GHz.toString()); - } + if (num24 > maxDisplayedScans) { + visibility.append("max=").append(maxRssi24).append(","); } + visibility.append(scans24GHz.toString()); } visibility.append(";"); if (num5 > 0) { visibility.append("(").append(num5).append(")"); - if (n5 <= 4) { - if (scans5GHz != null) { - visibility.append(scans5GHz.toString()); - } - } else { - visibility.append("max=").append(rssi5); - if (scans5GHz != null) { - visibility.append(",").append(scans5GHz.toString()); - } + if (num5 > maxDisplayedScans) { + visibility.append("max=").append(maxRssi5).append(","); } + visibility.append(scans5GHz.toString()); } if (numBlackListed > 0) visibility.append("!").append(numBlackListed); @@ -925,6 +905,28 @@ public class AccessPoint implements Comparable<AccessPoint> { return visibility.toString(); } + @VisibleForTesting + /* package */ String verboseScanResultSummary(ScanResult result, String bssid) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(" \n{").append(result.BSSID); + if (result.BSSID.equals(bssid)) { + stringBuilder.append("*"); + } + stringBuilder.append("=").append(result.frequency); + stringBuilder.append(",").append(result.level); + if (hasSpeed(result)) { + stringBuilder.append(",") + .append(getSpeedLabel(mScanResultScores.get(result.BSSID))); + } + stringBuilder.append("}"); + return stringBuilder.toString(); + } + + private boolean hasSpeed(ScanResult result) { + return mScanResultScores.containsKey(result.BSSID) + && mScanResultScores.get(result.BSSID) != Speed.NONE; + } + /** * Return whether this is the active connection. * For ephemeral connections (networkId is invalid), this returns false if the network is @@ -1135,7 +1137,12 @@ public class AccessPoint implements Comparable<AccessPoint> { @Nullable String getSpeedLabel() { - switch (mSpeed) { + return getSpeedLabel(mSpeed); + } + + @Nullable + private String getSpeedLabel(int speed) { + switch (speed) { case Speed.VERY_FAST: return mContext.getString(R.string.speed_label_very_fast); case Speed.FAST: diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 35c730e64ead..9645c9407600 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -73,6 +73,7 @@ public class AccessPointTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = InstrumentationRegistry.getTargetContext(); + WifiTracker.sVerboseLogging = false; } @Test @@ -426,7 +427,6 @@ public class AccessPointTest { ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); verify(mockWifiNetworkScoreCache, times(2)).getScoredNetwork(key); - verify(mockWifiNetworkScoreCache, never()).getScoredNetwork(any(ScanResult.class)); assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST); } @@ -444,6 +444,25 @@ public class AccessPointTest { } @Test + public void testVerboseSummaryString_showsScanResultSpeedLabel() { + WifiTracker.sVerboseLogging = true; + + Bundle bundle = new Bundle(); + ArrayList<ScanResult> scanResults = buildScanResultCache(); + bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, scanResults); + AccessPoint ap = new AccessPoint(mContext, bundle); + + when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) + .thenReturn(buildScoredNetworkWithMockBadgeCurve()); + when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST); + + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + String summary = ap.verboseScanResultSummary(scanResults.get(0), null); + + assertThat(summary.contains(mContext.getString(R.string.speed_label_very_fast))).isTrue(); + } + + @Test public void testSummaryString_concatenatesSpeedLabel() { AccessPoint ap = createAccessPointWithScanResultCache(); ap.update(new WifiConfiguration()); diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 862f8395b86c..7619ce2a7f71 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -756,7 +756,7 @@ <string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string> <string name="notification_channel_screenshot" msgid="6314080179230000938">"Էկրանի պատկերներ"</string> <string name="notification_channel_general" msgid="4525309436693914482">"Ընդհանուր հաղորդագրություններ"</string> - <string name="notification_channel_storage" msgid="3077205683020695313">"Հիշողություն"</string> + <string name="notification_channel_storage" msgid="3077205683020695313">"Տարածք"</string> <string name="instant_apps" msgid="6647570248119804907">"Ակնթարթորեն գործարկվող հավելվածներ"</string> <string name="instant_apps_message" msgid="8116608994995104836">"Ակնթարթորեն գործարկվող հավելվածները տեղադրում չեն պահանջում։"</string> <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index a64207714093..a9139993c137 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -22,6 +22,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.os.BatteryManager; @@ -56,6 +58,7 @@ public class PowerUI extends SystemUI { private PowerManager mPowerManager; private HardwarePropertiesManager mHardwarePropertiesManager; private WarningsUI mWarnings; + private final Configuration mLastConfiguration = new Configuration(); private int mBatteryLevel = 100; private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; private int mPlugType = 0; @@ -71,6 +74,11 @@ public class PowerUI extends SystemUI { private int mNumTemps; private long mNextLogTime; + // We create a method reference here so that we are guaranteed that we can remove a callback + // by using the same instance (method references are not guaranteed to be the same object + // each time they are created). + private final Runnable mUpdateTempCallback = this::updateTemperatureWarning; + public void start() { mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mHardwarePropertiesManager = (HardwarePropertiesManager) @@ -80,6 +88,7 @@ public class PowerUI extends SystemUI { mContext, (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE), getComponent(StatusBar.class)); + mLastConfiguration.setTo(mContext.getResources().getConfiguration()); ContentObserver obs = new ContentObserver(mHandler) { @Override @@ -101,6 +110,16 @@ public class PowerUI extends SystemUI { initTemperatureWarning(); } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + final int mask = ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; + + // Safe to modify mLastConfiguration here as it's only updated by the main thread (here). + if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) { + mHandler.post(this::initTemperatureWarning); + } + } + void updateBatteryWarningLevels() { int critLevel = mContext.getResources().getInteger( com.android.internal.R.integer.config_criticalBatteryWarningLevel); @@ -255,8 +274,14 @@ public class PowerUI extends SystemUI { } mThresholdTemp = throttlingTemps[0]; } + setNextLogTime(); + // This initialization method may be called on a configuration change. Only one set of + // ongoing callbacks should be occurring, so remove any now. updateTemperatureWarning will + // schedule an ongoing callback. + mHandler.removeCallbacks(mUpdateTempCallback); + // We have passed all of the checks, start checking the temp updateTemperatureWarning(); } @@ -288,7 +313,7 @@ public class PowerUI extends SystemUI { logTemperatureStats(); - mHandler.postDelayed(this::updateTemperatureWarning, TEMPERATURE_INTERVAL); + mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL); } private void logAtTemperatureThreshold(float temp) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 697db5fabcd8..10514a7f0c7f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -287,11 +287,17 @@ public class QSDetail extends LinearLayout { mScanState = state; final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable(); if (state) { - mQsDetailHeaderProgress.animate().alpha(1f); - anim.start(); + mQsDetailHeaderProgress.animate().cancel(); + mQsDetailHeaderProgress.animate() + .alpha(1) + .withEndAction(anim::start) + .start(); } else { - mQsDetailHeaderProgress.animate().alpha(0f); - anim.stop(); + mQsDetailHeaderProgress.animate().cancel(); + mQsDetailHeaderProgress.animate() + .alpha(0f) + .withEndAction(anim::stop) + .start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index f0d7d6c87833..2fc9fc7b09b0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -34,6 +34,7 @@ import android.view.View.OnAttachStateChangeListener; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; import android.widget.Button; import com.android.internal.app.MediaRouteChooserDialog; @@ -50,6 +51,7 @@ import com.android.systemui.qs.QSDetailItems; import com.android.systemui.qs.QSDetailItems.Item; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -139,25 +141,15 @@ public class CastTile extends QSTileImpl<BooleanState> { Dependency.get(ActivityStarter.class) .postStartActivityDismissingKeyguard(getLongClickIntent(), 0); }); - mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL); + mDialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG); + SystemUIDialog.setShowForAllUsers(mDialog, true); + SystemUIDialog.registerDismissListener(mDialog); + SystemUIDialog.setWindowOnTop(mDialog); mUiHandler.post(() -> mDialog.show()); - registerReceiver(); mHost.collapsePanels(); }); } - private void registerReceiver() { - mContext.registerReceiverAsUser(mReceiver, UserHandle.CURRENT, - new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, null); - mRegistered = true; - mDialog.setOnDismissListener(dialog -> { - if (mRegistered) { - mContext.unregisterReceiver(mReceiver); - mRegistered = false; - } - }); - } - @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_cast_title); @@ -223,15 +215,6 @@ public class CastTile extends QSTileImpl<BooleanState> { } }; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mDialog != null) { - mDialog.dismiss(); - } - } - }; - private final class CastDetailAdapter implements DetailAdapter, QSDetailItems.Callback { private final LinkedHashMap<String, CastDevice> mVisibleOrder = new LinkedHashMap<>(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 1e78e650bbf9..0e0f949ce42f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles; import android.app.AlertDialog; +import android.app.AlertDialog.Builder; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -27,12 +28,14 @@ import android.service.quicksettings.Tile; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager.LayoutParams; import android.widget.Switch; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.net.DataUsageController; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.R.string; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSIconView; @@ -111,11 +114,9 @@ public class CellularTile extends QSTileImpl<SignalState> { protected void handleClick() { if (mDataController.isMobileDataEnabled()) { if (mKeyguardMonitor.isSecure() && !mKeyguardMonitor.canSkipBouncer()) { - mActivityStarter.postQSRunnableDismissingKeyguard(() -> { - showDisableDialog(); - }); + mActivityStarter.postQSRunnableDismissingKeyguard(this::showDisableDialog); } else { - showDisableDialog(); + mUiHandler.post(this::showDisableDialog); } } else { mDataController.setMobileDataEnabled(true); @@ -124,13 +125,18 @@ public class CellularTile extends QSTileImpl<SignalState> { private void showDisableDialog() { mHost.collapsePanels(); - SystemUIDialog.applyFlags(new AlertDialog.Builder(mContext) - .setMessage(R.string.data_usage_disable_mobile) + AlertDialog dialog = new Builder(mContext) + .setMessage(string.data_usage_disable_mobile) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton( com.android.internal.R.string.alert_windows_notification_turn_off_action, (d, w) -> mDataController.setMobileDataEnabled(false)) - .create()).show(); + .create(); + dialog.getWindow().setType(LayoutParams.TYPE_KEYGUARD_DIALOG); + SystemUIDialog.setShowForAllUsers(dialog, true); + SystemUIDialog.registerDismissListener(dialog); + SystemUIDialog.setWindowOnTop(dialog); + dialog.show(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index cb8c39dad30a..136cf216f653 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -328,9 +328,6 @@ public class WifiTile extends QSTileImpl<SignalState> { filterUnreachableAPs(); updateItems(); - if (accessPoints != null && accessPoints.size() > 0) { - fireScanStateChanged(false); - } } /** Filter unreachable APs from mAccessPoints */ @@ -378,6 +375,12 @@ public class WifiTile extends QSTileImpl<SignalState> { private void updateItems() { if (mItems == null) return; + if ((mAccessPoints != null && mAccessPoints.length > 0) + || !mSignalCallback.mInfo.enabled) { + fireScanStateChanged(false); + } else { + fireScanStateChanged(true); + } // Wi-Fi is off if (!mSignalCallback.mInfo.enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 5b2b50bfe2f3..f9dd8bf5b202 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -379,7 +379,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, setScrimBehindAlpha(0f); } else if (mWakeAndUnlocking) { // During wake and unlock, we first hide everything behind a black scrim, which then - // gets faded out from animateKeyguardFadingOut. + // gets faded out from animateKeyguardFadingOut. This must never be animated. + mAnimateChange = false; if (mDozing) { setScrimInFrontAlpha(0f); setScrimBehindAlpha(1f); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 7b6725bfa392..9b0179dc4552 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -17,10 +17,18 @@ package com.android.systemui.statusbar.phone; import android.app.AlertDialog; +import android.app.Dialog; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.UserHandle; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.KeyguardMonitor; /** * Base class for dialogs that should appear over panels and keyguard. @@ -59,7 +67,7 @@ public class SystemUIDialog extends AlertDialog { setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick); } - public static void setShowForAllUsers(AlertDialog dialog, boolean show) { + public static void setShowForAllUsers(Dialog dialog, boolean show) { if (show) { dialog.getWindow().getAttributes().privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; @@ -69,10 +77,40 @@ public class SystemUIDialog extends AlertDialog { } } + public static void setWindowOnTop(Dialog dialog) { + if (Dependency.get(KeyguardMonitor.class).isShowing()) { + dialog.getWindow().setType(LayoutParams.TYPE_STATUS_BAR_PANEL); + } else { + dialog.getWindow().setType(LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); + } + } + public static AlertDialog applyFlags(AlertDialog dialog) { dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL); dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); return dialog; } + + public static void registerDismissListener(Dialog dialog) { + boolean[] registered = new boolean[1]; + Context context = dialog.getContext(); + final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (dialog != null) { + dialog.dismiss(); + } + } + }; + context.registerReceiverAsUser(mReceiver, UserHandle.CURRENT, + new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, null); + registered[0] = true; + dialog.setOnDismissListener(d -> { + if (registered[0]) { + context.unregisterReceiver(mReceiver); + registered[0] = false; + } + }); + } } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 41de97c8bcbb..d47ca1ccf17a 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -776,7 +776,9 @@ public class BackupManagerService implements BackupManagerServiceInterface { // side unpredictability. @Override public int generateRandomIntegerToken() { - int token = mTokenGenerator.nextInt() & ~0xFF; + int token = mTokenGenerator.nextInt(); + if (token < 0) token = -token; + token &= ~0xFF; token |= (mNextToken.incrementAndGet() & 0xFF); return token; } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index ce062aaa7d92..814e4be28ffa 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2110,7 +2110,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private boolean shouldShowImeSwitcherLocked(int visibility) { if (!mShowOngoingImeSwitcherForPhones) return false; if (mSwitchingDialog != null) return false; - if (isScreenLocked()) return false; + if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded() + && mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false; if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false; if (mWindowManagerInternal.isHardKeyboardAvailable()) { if (mHardKeyboardBehavior == HardKeyboardBehavior.WIRELESS_AFFORDANCE) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1281fb1fecb4..c435e3441148 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -23879,7 +23879,9 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target); return; } - ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration); + synchronized (ActivityManagerService.this) { + ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration); + } } @Override diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index f885167c7973..e25f3e65d3d8 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -76,6 +76,7 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.server.DeviceIdleController; +import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobStore.JobStatusFunctor; import com.android.server.job.controllers.AppIdleController; @@ -919,8 +920,57 @@ public final class JobSchedulerService extends com.android.server.SystemService mControllers.add(AppIdleController.get(this)); mControllers.add(ContentObserverController.get(this)); mControllers.add(DeviceIdleJobsController.get(this)); + + // If the job store determined that it can't yet reschedule persisted jobs, + // we need to start watching the clock. + if (!mJobs.jobTimesInflatedValid()) { + Slog.w(TAG, "!!! RTC not yet good; tracking time updates for job scheduling"); + context.registerReceiver(mTimeSetReceiver, new IntentFilter(Intent.ACTION_TIME_CHANGED)); + } } + private final BroadcastReceiver mTimeSetReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) { + // When we reach clock sanity, recalculate the temporal windows + // of all affected jobs. + if (mJobs.clockNowValidToInflate(System.currentTimeMillis())) { + Slog.i(TAG, "RTC now valid; recalculating persisted job windows"); + + // We've done our job now, so stop watching the time. + context.unregisterReceiver(this); + + // And kick off the work to update the affected jobs, using a secondary + // thread instead of chugging away here on the main looper thread. + FgThread.getHandler().post(mJobTimeUpdater); + } + } + } + }; + + private final Runnable mJobTimeUpdater = () -> { + final ArrayList<JobStatus> toRemove = new ArrayList<>(); + final ArrayList<JobStatus> toAdd = new ArrayList<>(); + synchronized (mLock) { + // Note: we intentionally both look up the existing affected jobs and replace them + // with recalculated ones inside the same lock lifetime. + getJobStore().getRtcCorrectedJobsLocked(toAdd, toRemove); + + // Now, at each position [i], we have both the existing JobStatus + // and the one that replaces it. + final int N = toAdd.size(); + for (int i = 0; i < N; i++) { + final JobStatus oldJob = toRemove.get(i); + final JobStatus newJob = toAdd.get(i); + if (DEBUG) { + Slog.v(TAG, " replacing " + oldJob + " with " + newJob); + } + cancelJobImplLocked(oldJob, newJob, "deferred rtc calculation"); + } + } + }; + @Override public void onStart() { publishLocalService(JobSchedulerInternal.class, new LocalService()); diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index a34e251f3608..031bdd0ee39c 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -219,6 +219,10 @@ public final class JobServiceContext implements ServiceConnection { isDeadlineExpired, triggeredUris, triggeredAuthorities); mExecutionStartTimeElapsed = SystemClock.elapsedRealtime(); + // Once we'e begun executing a job, we by definition no longer care whether + // it was inflated from disk with not-yet-coherent delay/deadline bounds. + job.clearPersistedUtcTimes(); + mVerb = VERB_BINDING; scheduleOpTimeOutLocked(); final Intent intent = new Intent().setComponent(job.getServiceComponent()); diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 84810bebf1f1..62b06d6242ea 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -72,10 +72,15 @@ public final class JobStore { /** Threshold to adjust how often we want to write to the db. */ private static final int MAX_OPS_BEFORE_WRITE = 1; + final Object mLock; final JobSet mJobSet; // per-caller-uid tracking final Context mContext; + // Bookkeeping around incorrect boot-time system clock + private final long mXmlTimestamp; + private boolean mRtcGood; + private int mDirtyOperations; private static final Object sSingletonLock = new Object(); @@ -120,7 +125,52 @@ public final class JobStore { mJobSet = new JobSet(); - readJobMapFromDisk(mJobSet); + // If the current RTC is earlier than the timestamp on our persisted jobs file, + // we suspect that the RTC is uninitialized and so we cannot draw conclusions + // about persisted job scheduling. + // + // Note that if the persisted jobs file does not exist, we proceed with the + // assumption that the RTC is good. This is less work and is safe: if the + // clock updates to sanity then we'll be saving the persisted jobs file in that + // correct state, which is normal; or we'll wind up writing the jobs file with + // an incorrect historical timestamp. That's fine; at worst we'll reboot with + // a *correct* timestamp, see a bunch of overdue jobs, and run them; then + // settle into normal operation. + mXmlTimestamp = mJobsFile.getLastModifiedTime(); + mRtcGood = (System.currentTimeMillis() > mXmlTimestamp); + + readJobMapFromDisk(mJobSet, mRtcGood); + } + + public boolean jobTimesInflatedValid() { + return mRtcGood; + } + + public boolean clockNowValidToInflate(long now) { + return now >= mXmlTimestamp; + } + + /** + * Find all the jobs that were affected by RTC clock uncertainty at boot time. Returns + * parallel lists of the existing JobStatus objects and of new, equivalent JobStatus instances + * with now-corrected time bounds. + */ + public void getRtcCorrectedJobsLocked(final ArrayList<JobStatus> toAdd, + final ArrayList<JobStatus> toRemove) { + final long elapsedNow = SystemClock.elapsedRealtime(); + + // Find the jobs that need to be fixed up, collecting them for post-iteration + // replacement with their new versions + forEachJob(job -> { + final Pair<Long, Long> utcTimes = job.getPersistedUtcTimes(); + if (utcTimes != null) { + Pair<Long, Long> elapsedRuntimes = + convertRtcBoundsToElapsed(utcTimes, elapsedNow); + toAdd.add(new JobStatus(job, elapsedRuntimes.first, elapsedRuntimes.second, + 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime())); + toRemove.add(job); + } + }); } /** @@ -241,8 +291,6 @@ public final class JobStore { /** * Every time the state changes we write all the jobs in one swath, instead of trying to * track incremental changes. - * @return Whether the operation was successful. This will only fail for e.g. if the system is - * low on storage. If this happens, we continue as normal */ private void maybeWriteStatusToDiskAsync() { mDirtyOperations++; @@ -250,20 +298,21 @@ public final class JobStore { if (DEBUG) { Slog.v(TAG, "Writing jobs to disk."); } - mIoHandler.post(new WriteJobsMapToDiskRunnable()); + mIoHandler.removeCallbacks(mWriteRunnable); + mIoHandler.post(mWriteRunnable); } } @VisibleForTesting - public void readJobMapFromDisk(JobSet jobSet) { - new ReadJobMapFromDiskRunnable(jobSet).run(); + public void readJobMapFromDisk(JobSet jobSet, boolean rtcGood) { + new ReadJobMapFromDiskRunnable(jobSet, rtcGood).run(); } /** * Runnable that writes {@link #mJobSet} out to xml. * NOTE: This Runnable locks on mLock */ - private final class WriteJobsMapToDiskRunnable implements Runnable { + private final Runnable mWriteRunnable = new Runnable() { @Override public void run() { final long startElapsed = SystemClock.elapsedRealtime(); @@ -280,7 +329,7 @@ public final class JobStore { }); } writeJobsMapImpl(storeCopy); - if (JobSchedulerService.DEBUG) { + if (DEBUG) { Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime() - startElapsed) + "ms"); } @@ -311,7 +360,7 @@ public final class JobStore { out.endTag(null, "job-info"); out.endDocument(); - // Write out to disk in one fell sweep. + // Write out to disk in one fell swoop. FileOutputStream fos = mJobsFile.startWrite(); fos.write(baos.toByteArray()); mJobsFile.finishWrite(fos); @@ -417,15 +466,27 @@ public final class JobStore { out.startTag(null, XML_TAG_ONEOFF); } + // If we still have the persisted times, we need to record those directly because + // we haven't yet been able to calculate the usual elapsed-timebase bounds + // correctly due to wall-clock uncertainty. + Pair <Long, Long> utcJobTimes = jobStatus.getPersistedUtcTimes(); + if (DEBUG && utcJobTimes != null) { + Slog.i(TAG, "storing original UTC timestamps for " + jobStatus); + } + + final long nowRTC = System.currentTimeMillis(); + final long nowElapsed = SystemClock.elapsedRealtime(); if (jobStatus.hasDeadlineConstraint()) { // Wall clock deadline. - final long deadlineWallclock = System.currentTimeMillis() + - (jobStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime()); + final long deadlineWallclock = (utcJobTimes == null) + ? nowRTC + (jobStatus.getLatestRunTimeElapsed() - nowElapsed) + : utcJobTimes.second; out.attribute(null, "deadline", Long.toString(deadlineWallclock)); } if (jobStatus.hasTimingDelayConstraint()) { - final long delayWallclock = System.currentTimeMillis() + - (jobStatus.getEarliestRunTime() - SystemClock.elapsedRealtime()); + final long delayWallclock = (utcJobTimes == null) + ? nowRTC + (jobStatus.getEarliestRunTime() - nowElapsed) + : utcJobTimes.first; out.attribute(null, "delay", Long.toString(delayWallclock)); } @@ -443,6 +504,25 @@ public final class JobStore { out.endTag(null, XML_TAG_ONEOFF); } } + }; + + /** + * Translate the supplied RTC times to the elapsed timebase, with clamping appropriate + * to interpreting them as a job's delay + deadline times for alarm-setting purposes. + * @param rtcTimes a Pair<Long, Long> in which {@code first} is the "delay" earliest + * allowable runtime for the job, and {@code second} is the "deadline" time at which + * the job becomes overdue. + */ + private static Pair<Long, Long> convertRtcBoundsToElapsed(Pair<Long, Long> rtcTimes, + long nowElapsed) { + final long nowWallclock = System.currentTimeMillis(); + final long earliest = (rtcTimes.first > JobStatus.NO_EARLIEST_RUNTIME) + ? nowElapsed + Math.max(rtcTimes.first - nowWallclock, 0) + : JobStatus.NO_EARLIEST_RUNTIME; + final long latest = (rtcTimes.second < JobStatus.NO_LATEST_RUNTIME) + ? nowElapsed + Math.max(rtcTimes.second - nowWallclock, 0) + : JobStatus.NO_LATEST_RUNTIME; + return Pair.create(earliest, latest); } /** @@ -451,13 +531,15 @@ public final class JobStore { */ private final class ReadJobMapFromDiskRunnable implements Runnable { private final JobSet jobSet; + private final boolean rtcGood; /** * @param jobSet Reference to the (empty) set of JobStatus objects that back the JobStore, * so that after disk read we can populate it directly. */ - ReadJobMapFromDiskRunnable(JobSet jobSet) { + ReadJobMapFromDiskRunnable(JobSet jobSet, boolean rtcIsGood) { this.jobSet = jobSet; + this.rtcGood = rtcIsGood; } @Override @@ -466,7 +548,7 @@ public final class JobStore { List<JobStatus> jobs; FileInputStream fis = mJobsFile.openRead(); synchronized (mLock) { - jobs = readJobMapImpl(fis); + jobs = readJobMapImpl(fis, rtcGood); if (jobs != null) { long now = SystemClock.elapsedRealtime(); IActivityManager am = ActivityManager.getService(); @@ -480,21 +562,21 @@ public final class JobStore { } fis.close(); } catch (FileNotFoundException e) { - if (JobSchedulerService.DEBUG) { + if (DEBUG) { Slog.d(TAG, "Could not find jobs file, probably there was nothing to load."); } } catch (XmlPullParserException e) { - if (JobSchedulerService.DEBUG) { + if (DEBUG) { Slog.d(TAG, "Error parsing xml.", e); } } catch (IOException e) { - if (JobSchedulerService.DEBUG) { + if (DEBUG) { Slog.d(TAG, "Error parsing xml.", e); } } } - private List<JobStatus> readJobMapImpl(FileInputStream fis) + private List<JobStatus> readJobMapImpl(FileInputStream fis, boolean rtcIsGood) throws XmlPullParserException, IOException { XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, StandardCharsets.UTF_8.name()); @@ -533,7 +615,7 @@ public final class JobStore { tagName = parser.getName(); // Start reading job. if ("job".equals(tagName)) { - JobStatus persistedJob = restoreJobFromXml(parser); + JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser); if (persistedJob != null) { if (DEBUG) { Slog.d(TAG, "Read out " + persistedJob); @@ -556,8 +638,8 @@ public final class JobStore { * will take the parser into the body of the job tag. * @return Newly instantiated job holding all the information we just read out of the xml tag. */ - private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException, - IOException { + private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser) + throws XmlPullParserException, IOException { JobInfo.Builder jobBuilder; int uid, sourceUserId; long lastSuccessfulRunTime; @@ -621,10 +703,10 @@ public final class JobStore { return null; } - // Tuple of (earliest runtime, latest runtime) in elapsed realtime after disk load. - Pair<Long, Long> elapsedRuntimes; + // Tuple of (earliest runtime, latest runtime) in UTC. + final Pair<Long, Long> rtcRuntimes; try { - elapsedRuntimes = buildExecutionTimesFromXml(parser); + rtcRuntimes = buildRtcExecutionTimesFromXml(parser); } catch (NumberFormatException e) { if (DEBUG) { Slog.d(TAG, "Error parsing execution time parameters, skipping."); @@ -633,6 +715,8 @@ public final class JobStore { } final long elapsedNow = SystemClock.elapsedRealtime(); + Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(rtcRuntimes, elapsedNow); + if (XML_TAG_PERIODIC.equals(parser.getName())) { try { String val = parser.getAttributeValue(null, "period"); @@ -722,7 +806,8 @@ public final class JobStore { JobStatus js = new JobStatus( jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag, elapsedRuntimes.first, elapsedRuntimes.second, - lastSuccessfulRunTime, lastFailedRunTime); + lastSuccessfulRunTime, lastFailedRunTime, + (rtcIsGood) ? null : rtcRuntimes); return js; } @@ -778,6 +863,32 @@ public final class JobStore { } /** + * Extract a job's earliest/latest run time data from XML. These are returned in + * unadjusted UTC wall clock time, because we do not yet know whether the system + * clock is reliable for purposes of calculating deltas from 'now'. + * + * @param parser + * @return A Pair of timestamps in UTC wall-clock time. The first is the earliest + * time at which the job is to become runnable, and the second is the deadline at + * which it becomes overdue to execute. + * @throws NumberFormatException + */ + private Pair<Long, Long> buildRtcExecutionTimesFromXml(XmlPullParser parser) + throws NumberFormatException { + String val; + // Pull out execution time data. + val = parser.getAttributeValue(null, "delay"); + final long earliestRunTimeRtc = (val != null) + ? Long.parseLong(val) + : JobStatus.NO_EARLIEST_RUNTIME; + val = parser.getAttributeValue(null, "deadline"); + final long latestRunTimeRtc = (val != null) + ? Long.parseLong(val) + : JobStatus.NO_LATEST_RUNTIME; + return Pair.create(earliestRunTimeRtc, latestRunTimeRtc); + } + + /** * Convenience function to read out and convert deadline and delay from xml into elapsed real * time. * @return A {@link android.util.Pair}, where the first value is the earliest elapsed runtime diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 9658da7a5de0..303b0007e1f7 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -28,10 +28,12 @@ import android.os.SystemClock; import android.os.UserHandle; import android.text.format.Time; import android.util.ArraySet; +import android.util.Pair; import android.util.Slog; import android.util.TimeUtils; import com.android.server.job.GrantedUriPermissions; +import com.android.server.job.JobSchedulerService; import java.io.PrintWriter; import java.util.ArrayList; @@ -50,6 +52,7 @@ import java.util.Arrays; */ public final class JobStatus { static final String TAG = "JobSchedulerService"; + static final boolean DEBUG = JobSchedulerService.DEBUG; public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE; public static final long NO_EARLIEST_RUNTIME = 0L; @@ -196,6 +199,18 @@ public final class JobStatus { private long mLastFailedRunTime; /** + * Transient: when a job is inflated from disk before we have a reliable RTC clock time, + * we retain the canonical (delay, deadline) scheduling tuple read out of the persistent + * store in UTC so that we can fix up the job's scheduling criteria once we get a good + * wall-clock time. If we have to persist the job again before the clock has been updated, + * we record these times again rather than calculating based on the earliest/latest elapsed + * time base figures. + * + * 'first' is the earliest/delay time, and 'second' is the latest/deadline time. + */ + private Pair<Long, Long> mPersistedUtcTimes; + + /** * For use only by ContentObserverController: state it is maintaining about content URIs * being observed. */ @@ -280,13 +295,20 @@ public final class JobStatus { mLastFailedRunTime = lastFailedRunTime; } - /** Copy constructor. */ + /** Copy constructor: used specifically when cloning JobStatus objects for persistence, + * so we preserve RTC window bounds if the source object has them. */ public JobStatus(JobStatus jobStatus) { this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(), jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(), jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime()); + mPersistedUtcTimes = jobStatus.mPersistedUtcTimes; + if (jobStatus.mPersistedUtcTimes != null) { + if (DEBUG) { + Slog.i(TAG, "Cloning job with persisted run times", new RuntimeException("here")); + } + } } /** @@ -298,10 +320,22 @@ public final class JobStatus { */ public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId, String sourceTag, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis, - long lastSuccessfulRunTime, long lastFailedRunTime) { + long lastSuccessfulRunTime, long lastFailedRunTime, + Pair<Long, Long> persistedExecutionTimesUTC) { this(job, callingUid, sourcePackageName, sourceUserId, sourceTag, 0, earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, lastSuccessfulRunTime, lastFailedRunTime); + + // Only during initial inflation do we record the UTC-timebase execution bounds + // read from the persistent store. If we ever have to recreate the JobStatus on + // the fly, it means we're rescheduling the job; and this means that the calculated + // elapsed timebase bounds intrinsically become correct. + this.mPersistedUtcTimes = persistedExecutionTimesUTC; + if (persistedExecutionTimesUTC != null) { + if (DEBUG) { + Slog.i(TAG, "+ restored job with RTC times because of bad boot clock"); + } + } } /** Create a new job to be rescheduled with the provided parameters. */ @@ -612,6 +646,14 @@ public final class JobStatus { return latestRunTimeElapsedMillis; } + public Pair<Long, Long> getPersistedUtcTimes() { + return mPersistedUtcTimes; + } + + public void clearPersistedUtcTimes() { + mPersistedUtcTimes = null; + } + boolean setChargingConstraintSatisfied(boolean state) { return setConstraintSatisfied(CONSTRAINT_CHARGING, state); } @@ -799,6 +841,9 @@ public final class JobStatus { if (job.isRequireDeviceIdle()) { sb.append(" IDLE"); } + if (job.isPeriodic()) { + sb.append(" PERIODIC"); + } if (job.isPersisted()) { sb.append(" PERSISTED"); } diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java index 62332c9235b0..c012ee41b29b 100644 --- a/services/core/java/com/android/server/location/GpsXtraDownloader.java +++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java @@ -41,6 +41,7 @@ public class GpsXtraDownloader { private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000; // 1MB. private static final String DEFAULT_USER_AGENT = "Android"; private static final int CONNECTION_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); + private static final int READ_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(60); private final String[] mXtraServers; // to load balance our server requests @@ -123,6 +124,7 @@ public class GpsXtraDownloader { "x-wap-profile", "http://www.openmobilealliance.org/tech/profiles/UAPROF/ccppschema-20021212#"); connection.setConnectTimeout(CONNECTION_TIMEOUT_MS); + connection.setReadTimeout(READ_TIMEOUT_MS); connection.connect(); int statusCode = connection.getResponseCode(); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index ee160eaa62d0..aabb24573084 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1265,13 +1265,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * @param subId that has its associated NetworkPolicy updated if necessary * @return if any policies were updated */ - private boolean maybeUpdateMobilePolicyCycleNL(int subId) { - if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleNL()"); - final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId); - - if (config == null) { - return false; - } + private boolean maybeUpdateMobilePolicyCycleAL(int subId) { + if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleAL()"); boolean policyUpdated = false; final String subscriberId = TelephonyManager.from(mContext).getSubscriberId(subId); @@ -1282,48 +1277,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { final NetworkTemplate template = mNetworkPolicy.keyAt(i); if (template.matches(probeIdent)) { - NetworkPolicy policy = mNetworkPolicy.valueAt(i); - - // only update the policy if the user didn't change any of the defaults. - if (!policy.inferred) { - // TODO: inferred could be split, so that if a user changes their data limit or - // warning, it doesn't prevent their cycle date from being updated. - if (LOGD) Slog.v(TAG, "Didn't update NetworkPolicy because policy.inferred"); - continue; - } - - final int currentCycleDay; - if (policy.cycleRule.isMonthly()) { - currentCycleDay = policy.cycleRule.start.getDayOfMonth(); - } else { - currentCycleDay = NetworkPolicy.CYCLE_NONE; - } - - final int cycleDay = getCycleDayFromCarrierConfig(config, currentCycleDay); - final long warningBytes = getWarningBytesFromCarrierConfig(config, - policy.warningBytes); - final long limitBytes = getLimitBytesFromCarrierConfig(config, - policy.limitBytes); - - if (currentCycleDay == cycleDay && - policy.warningBytes == warningBytes && - policy.limitBytes == limitBytes) { - continue; - } - - policyUpdated = true; - policy.cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.systemDefault()); - policy.warningBytes = warningBytes; - policy.limitBytes = limitBytes; - - if (LOGD) { - Slog.d(TAG, "Updated NetworkPolicy " + policy + " which matches subscriber " - + NetworkIdentity.scrubSubscriberId(subscriberId) - + " from CarrierConfigManager"); - } + final NetworkPolicy policy = mNetworkPolicy.valueAt(i); + policyUpdated |= updateDefaultMobilePolicyAL(subId, policy); } } - return policyUpdated; } @@ -1445,7 +1402,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mNetworkPoliciesSecondLock) { final boolean added = ensureActiveMobilePolicyAL(subId, subscriberId); if (added) return; - final boolean updated = maybeUpdateMobilePolicyCycleNL(subId); + final boolean updated = maybeUpdateMobilePolicyCycleAL(subId); if (!updated) return; // update network and notification rules, as the data cycle changed and it's // possible that we should be triggering warnings/limits now @@ -1602,12 +1559,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final NetworkPolicy policy = mNetworkRules.keyAt(i); final String[] ifaces = mNetworkRules.valueAt(i); - final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager - .cycleIterator(policy).next(); - final long start = cycle.first.toInstant().toEpochMilli(); - final long end = cycle.second.toInstant().toEpochMilli(); - final long totalBytes = getTotalBytes(policy.template, start, end); - if (LOGD) { Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces)); } @@ -1616,19 +1567,27 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED; if (hasLimit || policy.metered) { final long quotaBytes; - if (!hasLimit) { + if (hasLimit && policy.hasCycle()) { + final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager + .cycleIterator(policy).next(); + final long start = cycle.first.toInstant().toEpochMilli(); + final long end = cycle.second.toInstant().toEpochMilli(); + final long totalBytes = getTotalBytes(policy.template, start, end); + + if (policy.lastLimitSnooze >= start) { + // snoozing past quota, but we still need to restrict apps, + // so push really high quota. + quotaBytes = Long.MAX_VALUE; + } else { + // remaining "quota" bytes are based on total usage in + // current cycle. kernel doesn't like 0-byte rules, so we + // set 1-byte quota and disable the radio later. + quotaBytes = Math.max(1, policy.limitBytes - totalBytes); + } + } else { // metered network, but no policy limit; we still need to // restrict apps, so push really high quota. quotaBytes = Long.MAX_VALUE; - } else if (policy.lastLimitSnooze >= start) { - // snoozing past quota, but we still need to restrict apps, - // so push really high quota. - quotaBytes = Long.MAX_VALUE; - } else { - // remaining "quota" bytes are based on total usage in - // current cycle. kernel doesn't like 0-byte rules, so we - // set 1-byte quota and disable the radio later. - quotaBytes = Math.max(1, policy.limitBytes - totalBytes); } if (ifaces.length > 1) { @@ -1743,22 +1702,82 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @VisibleForTesting public NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) { - PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId); - - final int cycleDay = getCycleDayFromCarrierConfig(config, - ZonedDateTime.now().getDayOfMonth()); - final long warningBytes = getWarningBytesFromCarrierConfig(config, - getPlatformDefaultWarningBytes()); - final long limitBytes = getLimitBytesFromCarrierConfig(config, - getPlatformDefaultLimitBytes()); - final NetworkTemplate template = buildTemplateMobileAll(subscriberId); - final RecurrenceRule cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.systemDefault()); + final RecurrenceRule cycleRule = NetworkPolicy + .buildRule(ZonedDateTime.now().getDayOfMonth(), ZoneId.systemDefault()); final NetworkPolicy policy = new NetworkPolicy(template, cycleRule, - warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, true); + getPlatformDefaultWarningBytes(), getPlatformDefaultLimitBytes(), + SNOOZE_NEVER, SNOOZE_NEVER, true, true); + synchronized (mUidRulesFirstLock) { + synchronized (mNetworkPoliciesSecondLock) { + updateDefaultMobilePolicyAL(subId, policy); + } + } return policy; } + /** + * Update the given {@link NetworkPolicy} based on any carrier-provided + * defaults via {@link SubscriptionPlan} or {@link CarrierConfigManager}. + * Leaves policy untouched if the user has modified it. + * + * @return if the policy was modified + */ + private boolean updateDefaultMobilePolicyAL(int subId, NetworkPolicy policy) { + if (!policy.inferred) { + if (LOGD) Slog.d(TAG, "Ignoring user-defined policy " + policy); + return false; + } + + final NetworkPolicy original = new NetworkPolicy(policy.template, policy.cycleRule, + policy.warningBytes, policy.limitBytes, policy.lastWarningSnooze, + policy.lastLimitSnooze, policy.metered, policy.inferred); + + final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId); + if (!ArrayUtils.isEmpty(plans)) { + final SubscriptionPlan plan = plans[0]; + policy.cycleRule = plan.getCycleRule(); + final long planLimitBytes = plan.getDataLimitBytes(); + if (planLimitBytes == SubscriptionPlan.BYTES_UNKNOWN) { + policy.warningBytes = getPlatformDefaultWarningBytes(); + policy.limitBytes = getPlatformDefaultLimitBytes(); + } else if (planLimitBytes == SubscriptionPlan.BYTES_UNLIMITED) { + policy.warningBytes = NetworkPolicy.WARNING_DISABLED; + policy.limitBytes = NetworkPolicy.LIMIT_DISABLED; + } else { + policy.warningBytes = (planLimitBytes * 9) / 10; + switch (plan.getDataLimitBehavior()) { + case SubscriptionPlan.LIMIT_BEHAVIOR_BILLED: + case SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED: + policy.limitBytes = planLimitBytes; + break; + default: + policy.limitBytes = NetworkPolicy.LIMIT_DISABLED; + break; + } + } + } else { + final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId); + final int currentCycleDay; + if (policy.cycleRule.isMonthly()) { + currentCycleDay = policy.cycleRule.start.getDayOfMonth(); + } else { + currentCycleDay = NetworkPolicy.CYCLE_NONE; + } + final int cycleDay = getCycleDayFromCarrierConfig(config, currentCycleDay); + policy.cycleRule = NetworkPolicy.buildRule(cycleDay, ZoneId.systemDefault()); + policy.warningBytes = getWarningBytesFromCarrierConfig(config, policy.warningBytes); + policy.limitBytes = getLimitBytesFromCarrierConfig(config, policy.limitBytes); + } + + if (policy.equals(original)) { + return false; + } else { + Slog.d(TAG, "Updated " + original + " to " + policy); + return true; + } + } + private void readPolicyAL() { if (LOGV) Slog.v(TAG, "readPolicyAL()"); @@ -2790,8 +2809,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mNetworkPoliciesSecondLock) { mSubscriptionPlans.put(subId, plans); mSubscriptionPlansOwner.put(subId, callingPackage); - // TODO: update any implicit details from newly defined plans - handleNetworkPoliciesUpdateAL(false); + + final String subscriberId = mContext.getSystemService(TelephonyManager.class) + .getSubscriberId(subId); + ensureActiveMobilePolicyAL(subId, subscriberId); + maybeUpdateMobilePolicyCycleAL(subId); + handleNetworkPoliciesUpdateAL(true); } } } finally { @@ -2827,6 +2850,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); + fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces)); + + fout.println(); fout.println("Network policies:"); fout.increaseIndent(); for (int i = 0; i < mNetworkPolicy.size(); i++) { @@ -2834,8 +2860,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } fout.decreaseIndent(); - fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces)); + fout.println(); + fout.println("Subscription plans:"); + fout.increaseIndent(); + for (int i = 0; i < mSubscriptionPlans.size(); i++) { + final int subId = mSubscriptionPlans.keyAt(i); + fout.println("Subscriber ID " + subId + ":"); + fout.increaseIndent(); + final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i); + if (!ArrayUtils.isEmpty(plans)) { + for (SubscriptionPlan plan : plans) { + fout.println(plan); + } + } + fout.decreaseIndent(); + } + fout.decreaseIndent(); + fout.println(); fout.println("Policy for UIDs:"); fout.increaseIndent(); int size = mUidPolicy.size(); diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 41bc7f2cd4c3..dabd35c1fc14 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -33,12 +33,12 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; +import com.android.server.pm.dex.PackageDexUsage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Set; import dalvik.system.DexFile; @@ -251,13 +251,12 @@ public class PackageDexOptimizer { * throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though * that seems wasteful. */ - public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas, - String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) { + public int dexOptSecondaryDexPath(ApplicationInfo info, String path, + PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { synchronized (mInstallLock) { final long acquireTime = acquireWakeLockLI(info.uid); try { - return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter, - isUsedByOtherApps, downgrade); + return dexOptSecondaryDexPathLI(info, path, dexUseInfo, options); } finally { releaseWakeLockLI(acquireTime); } @@ -298,9 +297,16 @@ public class PackageDexOptimizer { } @GuardedBy("mInstallLock") - private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas, - String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) { - compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps); + private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, + PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { + if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) { + // We are asked to optimize only the dex files used by other apps and this is not + // on of them: skip it. + return DEX_OPT_SKIPPED; + } + + String compilerFilter = getRealCompilerFilter(info, options.getCompilerFilter(), + dexUseInfo.isUsedByOtherApps()); // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags. // Secondary dex files are currently not compiled at boot. int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true) @@ -317,20 +323,32 @@ public class PackageDexOptimizer { return DEX_OPT_FAILED; } Log.d(TAG, "Running dexopt on: " + path - + " pkg=" + info.packageName + " isa=" + isas + + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() + " dexoptFlags=" + printDexoptFlags(dexoptFlags) + " target-filter=" + compilerFilter); + String classLoaderContext; + if (dexUseInfo.isUnknownClassLoaderContext() || + dexUseInfo.isUnsupportedClassLoaderContext() || + dexUseInfo.isVariableClassLoaderContext()) { + // If we have an unknown (not yet set), unsupported (custom class loaders), or a + // variable class loader chain, compile without a context and mark the oat file with + // SKIP_SHARED_LIBRARY_CHECK. Note that his might lead to a incorrect compilation. + // TODO(calin): We should just extract in this case. + classLoaderContext = SKIP_SHARED_LIBRARY_CHECK; + } else { + classLoaderContext = dexUseInfo.getClassLoaderContext(); + } try { - for (String isa : isas) { + for (String isa : dexUseInfo.getLoaderIsas()) { // Reuse the same dexopt path as for the primary apks. We don't need all the // arguments as some (dexopNeeded and oatDir) will be computed by installd because // system server cannot read untrusted app content. // TODO(calin): maybe add a separate call. mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, /*oatDir*/ null, dexoptFlags, - compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK, info.seInfoUser, - downgrade); + compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser, + options.isDowngrade()); } return DEX_OPT_PERFORMED; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c128a0e49e83..32fe61656e2f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9686,7 +9686,8 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void notifyDexLoad(String loadingPackageName, List<String> dexPaths, String loaderIsa) { + public void notifyDexLoad(String loadingPackageName, List<String> classLoaderNames, + List<String> classPaths, String loaderIsa) { int userId = UserHandle.getCallingUserId(); ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId); if (ai == null) { @@ -9694,7 +9695,7 @@ public class PackageManagerService extends IPackageManager.Stub + loadingPackageName + ", user=" + userId); return; } - mDexManager.notifyDexLoad(ai, dexPaths, loaderIsa, userId); + mDexManager.notifyDexLoad(ai, classLoaderNames, classPaths, loaderIsa, userId); } @Override diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 3d2d4833175b..79e02b5399de 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -97,29 +97,55 @@ public class DexManager { * return as fast as possible. * * @param loadingAppInfo the package performing the load - * @param dexPaths the list of dex files being loaded + * @param classLoadersNames the names of the class loaders present in the loading chain. The + * list encodes the class loader chain in the natural order. The first class loader has + * the second one as its parent and so on. The dex files present in the class path of the + * first class loader will be recorded in the usage file. + * @param classPaths the class paths corresponding to the class loaders names from + * {@param classLoadersNames}. The the first element corresponds to the first class loader + * and so on. A classpath is represented as a list of dex files separated by + * {@code File.pathSeparator}. + * The dex files found in the first class path will be recorded in the usage file. * @param loaderIsa the ISA of the app loading the dex files * @param loaderUserId the user id which runs the code loading the dex files */ - public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> dexPaths, - String loaderIsa, int loaderUserId) { + public void notifyDexLoad(ApplicationInfo loadingAppInfo, List<String> classLoadersNames, + List<String> classPaths, String loaderIsa, int loaderUserId) { try { - notifyDexLoadInternal(loadingAppInfo, dexPaths, loaderIsa, loaderUserId); + notifyDexLoadInternal(loadingAppInfo, classLoadersNames, classPaths, loaderIsa, + loaderUserId); } catch (Exception e) { Slog.w(TAG, "Exception while notifying dex load for package " + loadingAppInfo.packageName, e); } } - private void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, List<String> dexPaths, - String loaderIsa, int loaderUserId) { + private void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, + List<String> classLoaderNames, List<String> classPaths, String loaderIsa, + int loaderUserId) { + if (classLoaderNames.size() != classPaths.size()) { + Slog.wtf(TAG, "Bad call to noitfyDexLoad: args have different size"); + return; + } + if (classLoaderNames.isEmpty()) { + Slog.wtf(TAG, "Bad call to notifyDexLoad: class loaders list is empty"); + return; + } if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { - Slog.w(TAG, "Loading dex files " + dexPaths + " in unsupported ISA: " + + Slog.w(TAG, "Loading dex files " + classPaths + " in unsupported ISA: " + loaderIsa + "?"); return; } - for (String dexPath : dexPaths) { + // The classpath is represented as a list of dex files separated by File.pathSeparator. + String[] dexPathsToRegister = classPaths.get(0).split(File.pathSeparator); + + // Encode the class loader contexts for the dexPathsToRegister. + String[] classLoaderContexts = DexoptUtils.processContextForDexLoad( + classLoaderNames, classPaths); + + int dexPathIndex = 0; + for (String dexPath : dexPathsToRegister) { // Find the owning package name. DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId); @@ -147,24 +173,25 @@ public class DexManager { // Record dex file usage. If the current usage is a new pattern (e.g. new secondary, // or UsedBytOtherApps), record will return true and we trigger an async write // to disk to make sure we don't loose the data in case of a reboot. + + // A null classLoaderContexts means that there are unsupported class loaders in the + // chain. + String classLoaderContext = classLoaderContexts == null + ? PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT + : classLoaderContexts[dexPathIndex]; if (mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, - loadingAppInfo.packageName)) { + loadingAppInfo.packageName, classLoaderContext)) { mPackageDexUsage.maybeWriteAsync(); } } else { - // This can happen in a few situations: - // - bogus dex loads - // - recent installs/uninstalls that we didn't detect. - // - new installed splits // If we can't find the owner of the dex we simply do not track it. The impact is // that the dex file will not be considered for offline optimizations. - // TODO(calin): add hooks for move/uninstall notifications to - // capture package moves or obsolete packages. if (DEBUG) { Slog.i(TAG, "Could not find owning package for dex file: " + dexPath); } } + dexPathIndex++; } } @@ -328,10 +355,8 @@ public class DexManager { for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) { String dexPath = entry.getKey(); DexUseInfo dexUseInfo = entry.getValue(); - if (options.isDexoptOnlySharedDex() && !dexUseInfo.isUsedByOtherApps()) { - continue; - } - PackageInfo pkg = null; + + PackageInfo pkg; try { pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0, dexUseInfo.getOwnerUserId()); @@ -350,8 +375,7 @@ public class DexManager { } int result = pdo.dexOptSecondaryDexPath(pkg.applicationInfo, dexPath, - dexUseInfo.getLoaderIsas(), options.getCompilerFilter(), - dexUseInfo.isUsedByOtherApps(), options.isDowngrade()); + dexUseInfo, options); success = success && (result != PackageDexOptimizer.DEX_OPT_FAILED); } return success; @@ -434,6 +458,8 @@ public class DexManager { } } + // TODO(calin): questionable API in the presence of class loaders context. Needs amends as the + // compilation happening here will use a pessimistic context. public RegisterDexModuleResult registerDexModule(ApplicationInfo info, String dexPath, boolean isUsedByOtherApps, int userId) { // Find the owning package record. @@ -452,12 +478,11 @@ public class DexManager { // We found the package. Now record the usage for all declared ISAs. boolean update = false; - Set<String> isas = new HashSet<>(); for (String isa : getAppDexInstructionSets(info)) { - isas.add(isa); boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false, - searchResult.mOwningPackageName); + searchResult.mOwningPackageName, + PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT); update |= newUpdate; } if (update) { @@ -467,8 +492,13 @@ public class DexManager { // Try to optimize the package according to the install reason. String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason( PackageManagerService.REASON_INSTALL); - int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, isas, - compilerFilter, isUsedByOtherApps, /* downgrade */ false); + DexUseInfo dexUseInfo = mPackageDexUsage.getPackageUseInfo(searchResult.mOwningPackageName) + .getDexUseInfoMap().get(dexPath); + + DexoptOptions options = new DexoptOptions(info.packageName, compilerFilter, /*flags*/0); + + int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, dexUseInfo, + options); // If we fail to optimize the package log an error but don't propagate the error // back to the app. The app cannot do much about it and the background job diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 18e91dfe57a1..0196212d6bc2 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -23,6 +23,8 @@ import android.util.SparseArray; import com.android.internal.os.ClassLoaderFactory; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public final class DexoptUtils { @@ -229,7 +231,76 @@ public final class DexoptUtils { * dependencies {@see encodeClassLoader} separated by ';'. */ private static String encodeClassLoaderChain(String cl1, String cl2) { - return cl1.isEmpty() ? cl2 : (cl1 + ";" + cl2); + if (cl1.isEmpty()) return cl2; + if (cl2.isEmpty()) return cl1; + return cl1 + ";" + cl2; + } + + /** + * Compute the class loader context for the dex files present in the classpath of the first + * class loader from the given list (referred in the code as the {@code loadingClassLoader}). + * Each dex files gets its own class loader context in the returned array. + * + * Example: + * If classLoadersNames = {"dalvik.system.DelegateLastClassLoader", + * "dalvik.system.PathClassLoader"} and classPaths = {"foo.dex:bar.dex", "other.dex"} + * The output will be + * {"DLC[];PCL[other.dex]", "DLC[foo.dex];PCL[other.dex]"} + * with "DLC[];PCL[other.dex]" being the context for "foo.dex" + * and "DLC[foo.dex];PCL[other.dex]" the context for "bar.dex". + * + * If any of the class loaders names is unsupported the method will return null. + * + * The argument lists must be non empty and of the same size. + * + * @param classLoadersNames the names of the class loaders present in the loading chain. The + * list encodes the class loader chain in the natural order. The first class loader has + * the second one as its parent and so on. + * @param classPaths the class paths for the elements of {@param classLoadersNames}. The + * the first element corresponds to the first class loader and so on. A classpath is + * represented as a list of dex files separated by {@code File.pathSeparator}. + * The return context will be for the dex files found in the first class path. + */ + /*package*/ static String[] processContextForDexLoad(List<String> classLoadersNames, + List<String> classPaths) { + if (classLoadersNames.size() != classPaths.size()) { + throw new IllegalArgumentException( + "The size of the class loader names and the dex paths do not match."); + } + if (classLoadersNames.isEmpty()) { + throw new IllegalArgumentException("Empty classLoadersNames"); + } + + // Compute the context for the parent class loaders. + String parentContext = ""; + // We know that these lists are actually ArrayLists so getting the elements by index + // is fine (they come over binder). Even if something changes we expect the sizes to be + // very small and it shouldn't matter much. + for (int i = 1; i < classLoadersNames.size(); i++) { + if (!ClassLoaderFactory.isValidClassLoaderName(classLoadersNames.get(i))) { + return null; + } + String classpath = encodeClasspath(classPaths.get(i).split(File.pathSeparator)); + parentContext = encodeClassLoaderChain(parentContext, + encodeClassLoader(classpath, classLoadersNames.get(i))); + } + + // Now compute the class loader context for each dex file from the first classpath. + String loadingClassLoader = classLoadersNames.get(0); + if (!ClassLoaderFactory.isValidClassLoaderName(loadingClassLoader)) { + return null; + } + String[] loadedDexPaths = classPaths.get(0).split(File.pathSeparator); + String[] loadedDexPathsContext = new String[loadedDexPaths.length]; + String currentLoadedDexPathClasspath = ""; + for (int i = 0; i < loadedDexPaths.length; i++) { + String dexPath = loadedDexPaths[i]; + String currentContext = encodeClassLoader( + currentLoadedDexPathClasspath, loadingClassLoader); + loadedDexPathsContext[i] = encodeClassLoaderChain(currentContext, parentContext); + currentLoadedDexPathClasspath = encodeClasspath(currentLoadedDexPathClasspath, dexPath); + } + return loadedDexPathsContext; } /** diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java index f7dd174847a1..8819aa66ed6b 100644 --- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java +++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java @@ -26,7 +26,6 @@ import com.android.server.pm.AbstractStatsBase; import com.android.server.pm.PackageManagerServiceUtils; import java.io.BufferedReader; -import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; @@ -36,7 +35,6 @@ import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.HashMap; @@ -55,10 +53,12 @@ import libcore.util.Objects; public class PackageDexUsage extends AbstractStatsBase<Void> { private final static String TAG = "PackageDexUsage"; - // The last version update: add the list of packages that load the dex files. - private final static int PACKAGE_DEX_USAGE_VERSION = 2; - // We support VERSION 1 to ensure that the usage list remains valid cross OTAs. + // The last version update: add class loader contexts for secondary dex files. + private final static int PACKAGE_DEX_USAGE_VERSION = 3; + // We support previous version to ensure that the usage list remains valid cross OTAs. private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 = 1; + // Version 2 added the list of packages that load the dex files. + private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2 = 2; private final static String PACKAGE_DEX_USAGE_VERSION_HEADER = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__"; @@ -66,6 +66,21 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { private final static String SPLIT_CHAR = ","; private final static String DEX_LINE_CHAR = "#"; private final static String LOADING_PACKAGE_CHAR = "@"; + + // One of the things we record about dex files is the class loader context that was used to + // load them. That should be stable but if it changes we don't keep track of variable contexts. + // Instead we put a special marker in the dex usage file in order to recognize the case and + // skip optimizations on that dex files. + /*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT = + "=VariableClassLoaderContext="; + // The marker used for unsupported class loader contexts. + /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = + "=UnsupportedClassLoaderContext="; + // The markers used for unknown class loader contexts. This can happen if the dex file was + // recorded in a previous version and we didn't have a chance to update its usage. + /*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT = + "=UnknownClassLoaderContext="; + // Map which structures the information we have on a package. // Maps package name to package data (which stores info about UsedByOtherApps and // secondary dex files.). @@ -98,10 +113,14 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { */ public boolean record(String owningPackageName, String dexPath, int ownerUserId, String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, - String loadingPackageName) { + String loadingPackageName, String classLoaderContext) { if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported"); } + if (classLoaderContext == null) { + throw new IllegalArgumentException("Null classLoaderContext"); + } + synchronized (mPackageUseInfoMap) { PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName); if (packageUseInfo == null) { @@ -117,7 +136,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } else { // For secondary dex files record the loaderISA and the owner. We'll need // to know under which user to compile and for what ISA. - DexUseInfo newData = new DexUseInfo(isUsedByOtherApps, ownerUserId, loaderIsa); + DexUseInfo newData = new DexUseInfo(isUsedByOtherApps, ownerUserId, + classLoaderContext, loaderIsa); packageUseInfo.mDexUseInfoMap.put(dexPath, newData); maybeAddLoadingPackage(owningPackageName, loadingPackageName, newData.mLoadingPackages); @@ -134,7 +154,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { return packageUseInfo.merge(isUsedByOtherApps) || updateLoadingPackages; } else { DexUseInfo newData = new DexUseInfo( - isUsedByOtherApps, ownerUserId, loaderIsa); + isUsedByOtherApps, ownerUserId, classLoaderContext, loaderIsa); boolean updateLoadingPackages = maybeAddLoadingPackage(owningPackageName, loadingPackageName, newData.mLoadingPackages); @@ -249,8 +269,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { String dexPath = dEntry.getKey(); DexUseInfo dexUseInfo = dEntry.getValue(); fpw.println(DEX_LINE_CHAR + dexPath); - fpw.println(LOADING_PACKAGE_CHAR + - String.join(SPLIT_CHAR, dexUseInfo.mLoadingPackages)); + fpw.println(LOADING_PACKAGE_CHAR + + String.join(SPLIT_CHAR, dexUseInfo.mLoadingPackages)); + fpw.println(dexUseInfo.getClassLoaderContext()); fpw.print(String.join(SPLIT_CHAR, Integer.toString(dexUseInfo.mOwnerUserId), writeBoolean(dexUseInfo.mIsUsedByOtherApps))); @@ -310,8 +331,10 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { while ((s = in.readLine()) != null) { if (s.startsWith(DEX_LINE_CHAR)) { // This is the start of the the dex lines. - // We expect two lines for each dex entry: + // We expect 4 lines for each dex entry: // #dexPaths + // @loading_package_1,loading_package_2,... + // class_loader_context // onwerUserId,isUsedByOtherApps,isa1,isa2 if (currentPackage == null) { throw new IllegalStateException( @@ -323,11 +346,13 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // In version 2 the second line contains the list of packages that loaded the file. List<String> loadingPackages = maybeReadLoadingPackages(in, version); + // In version 3 the third line contains the class loader context. + String classLoaderContext = maybeReadClassLoaderContext(in, version); // Next line is the dex data. s = in.readLine(); if (s == null) { - throw new IllegalStateException("Could not find dexUseInfo for line: " + s); + throw new IllegalStateException("Could not find dexUseInfo line"); } // We expect at least 3 elements (isUsedByOtherApps, userId, isa). @@ -337,9 +362,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } int ownerUserId = Integer.parseInt(elems[0]); boolean isUsedByOtherApps = readBoolean(elems[1]); - DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId); + DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId, + classLoaderContext, /*isa*/ null); dexUseInfo.mLoadingPackages.addAll(loadingPackages); - for (int i = 2; i < elems.length; i++) { String isa = elems[i]; if (supportedIsas.contains(isa)) { @@ -379,12 +404,30 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } /** - * Reads the list of loading packages from the buffer {@parm in} if + * Reads the class loader context encoding from the buffer {@code in} if * {@code version} is at least {PACKAGE_DEX_USAGE_VERSION}. */ + private String maybeReadClassLoaderContext(BufferedReader in, int version) throws IOException { + String context = null; + if (version == PACKAGE_DEX_USAGE_VERSION) { + context = in.readLine(); + if (context == null) { + throw new IllegalStateException("Could not find the classLoaderContext line."); + } + } + // The context might be empty if we didn't have the chance to update it after a version + // upgrade. In this case return the special marker so that we recognize this is an unknown + // context. + return context == null ? UNKNOWN_CLASS_LOADER_CONTEXT : context; + } + + /** + * Reads the list of loading packages from the buffer {@code in} if + * {@code version} is at least {PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2}. + */ private List<String> maybeReadLoadingPackages(BufferedReader in, int version) throws IOException { - if (version == PACKAGE_DEX_USAGE_VERSION) { + if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) { String line = in.readLine(); if (line == null) { throw new IllegalStateException("Could not find the loadingPackages line."); @@ -660,17 +703,20 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public static class DexUseInfo { private boolean mIsUsedByOtherApps; private final int mOwnerUserId; + // The class loader context for the dex file. This encodes the class loader chain + // (class loader type + class path) in a format compatible to dex2oat. + // See {@code DexoptUtils.processContextForDexLoad}. + private String mClassLoaderContext; + // The instructions sets of the applications loading the dex file. private final Set<String> mLoaderIsas; // Packages who load this dex file. private final Set<String> mLoadingPackages; - public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId) { - this(isUsedByOtherApps, ownerUserId, null); - } - - public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String loaderIsa) { + public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext, + String loaderIsa) { mIsUsedByOtherApps = isUsedByOtherApps; mOwnerUserId = ownerUserId; + mClassLoaderContext = classLoaderContext; mLoaderIsas = new HashSet<>(); if (loaderIsa != null) { mLoaderIsas.add(loaderIsa); @@ -682,6 +728,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public DexUseInfo(DexUseInfo other) { mIsUsedByOtherApps = other.mIsUsedByOtherApps; mOwnerUserId = other.mOwnerUserId; + mClassLoaderContext = other.mClassLoaderContext; mLoaderIsas = new HashSet<>(other.mLoaderIsas); mLoadingPackages = new HashSet<>(other.mLoadingPackages); } @@ -691,8 +738,24 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps; boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas); boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages); - return updateIsas || (oldIsUsedByOtherApps != mIsUsedByOtherApps) || - updateLoadingPackages; + + String oldClassLoaderContext = mClassLoaderContext; + if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) { + // Can happen if we read a previous version. + mClassLoaderContext = dexUseInfo.mClassLoaderContext; + } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) { + // We detected an unsupported context. + mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT; + } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) && + !Objects.equal(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { + // We detected a context change. + mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT; + } + + return updateIsas || + (oldIsUsedByOtherApps != mIsUsedByOtherApps) || + updateLoadingPackages + || !Objects.equal(oldClassLoaderContext, mClassLoaderContext); } public boolean isUsedByOtherApps() { @@ -710,5 +773,21 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public Set<String> getLoadingPackages() { return mLoadingPackages; } + + public String getClassLoaderContext() { return mClassLoaderContext; } + + public boolean isUnsupportedClassLoaderContext() { + return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); + } + + public boolean isUnknownClassLoaderContext() { + // The class loader context may be unknown if we loaded the data from a previous version + // which didn't save the context. + return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); + } + + public boolean isVariableClassLoaderContext() { + return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); + } } } diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java index 9b4999667c88..24e0fe4841bc 100644 --- a/services/core/java/com/android/server/timezone/PackageTracker.java +++ b/services/core/java/com/android/server/timezone/PackageTracker.java @@ -173,8 +173,6 @@ public class PackageTracker implements IntentHelper.Listener { throw logAndThrowRuntimeException("Could not determine update app package details for " + mUpdateAppPackageName, e); } - // TODO(nfuller) Consider permission checks. While an updated system app retains permissions - // obtained by the system version it's not clear how to check them. Slog.d(TAG, "Update app " + mUpdateAppPackageName + " is valid."); // Validate the data application package. @@ -187,8 +185,6 @@ public class PackageTracker implements IntentHelper.Listener { throw logAndThrowRuntimeException("Could not determine data app package details for " + mDataAppPackageName, e); } - // TODO(nfuller) Consider permission checks. While an updated system app retains permissions - // obtained by the system version it's not clear how to check them. Slog.d(TAG, "Data app " + mDataAppPackageName + " is valid."); } @@ -466,7 +462,6 @@ public class PackageTracker implements IntentHelper.Listener { + TimeZoneRulesDataContract.AUTHORITY); return false; } - // TODO(nfuller) Add any permissions checks needed. return true; } diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 74c1b24ede28..425b23f29d0f 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -1125,8 +1125,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC private void setPersistentVrModeEnabled(boolean enabled) { synchronized(mLock) { setPersistentModeAndNotifyListenersLocked(enabled); - // Disabling persistent mode when not showing a VR should disable the overall vr mode. - if (!enabled && mCurrentVrModeComponent == null) { + // Disabling persistent mode should disable the overall vr mode. + if (!enabled) { setVrMode(false, null, 0, -1, null); } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 63890bf346ef..c4ff455fa3d3 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1311,7 +1311,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to // an Activity in another task being started in the wrong orientation during the transition. if (!(sendingToBottom || mService.mClosingApps.contains(this)) - && (isVisible() || mService.mOpeningApps.contains(this))) { + && (isVisible() || mService.mOpeningApps.contains(this) || isOnTop())) { return mOrientation; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 55c0612ff764..4d77d40584c1 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3308,6 +3308,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo setLayoutNeeded(); } + + @Override + boolean isOnTop() { + // Considered always on top + return true; + } + @Override void positionChildAt(int position, TaskStack child, boolean includingParents) { if (StackId.isAlwaysOnTop(child.mStackId) && position != POSITION_TOP) { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 600bc5c47062..3df73d7c627a 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -472,6 +472,13 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon return false; } + /** +a * Returns whether this child is on top of the window hierarchy. + */ + boolean isOnTop() { + return getParent().getTopChild() == this && getParent().isOnTop(); + } + /** Returns the top child container. */ E getTopChild() { return mChildren.peekLast(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 61267ef5047a..a1b9099f8bab 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -34,6 +34,7 @@ import android.os.FactoryTest; import android.os.FileUtils; import android.os.IIncidentManager; import android.os.Looper; +import android.os.Message; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -463,7 +464,20 @@ public final class SystemServer { } } } - ShutdownThread.rebootOrShutdown(null, reboot, reason); + Runnable runnable = new Runnable() { + @Override + public void run() { + synchronized (this) { + ShutdownThread.rebootOrShutdown(null, reboot, reason); + } + } + }; + + // ShutdownThread must run on a looper capable of displaying the UI. + Message msg = Message.obtain(UiThread.getHandler(), runnable); + msg.setAsynchronous(true); + UiThread.getHandler().sendMessage(msg); + } } @@ -1203,7 +1217,7 @@ public final class SystemServer { if (startRulesManagerService) { traceBeginAndSlog("StartTimeZoneRulesManagerService"); mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + traceEnd(); } traceBeginAndSlog("StartAudioService"); diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 6c417a9baf93..5121c29d688d 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -736,14 +736,18 @@ public final class PrintManagerService extends SystemService { UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false, false /* enforceUserUnlockingOrUnlocked */); + boolean prunePrintServices = false; synchronized (mLock) { if (hadPrintService(userState, packageName) || hasPrintService(packageName)) { userState.updateIfNeededLocked(); + prunePrintServices = true; } } - userState.prunePrintServices(); + if (prunePrintServices) { + userState.prunePrintServices(); + } } @Override @@ -752,13 +756,17 @@ public final class PrintManagerService extends SystemService { UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false, false /* enforceUserUnlockingOrUnlocked */); + boolean prunePrintServices = false; synchronized (mLock) { if (hadPrintService(userState, packageName)) { userState.updateIfNeededLocked(); + prunePrintServices = true; } } - userState.prunePrintServices(); + if (prunePrintServices) { + userState.prunePrintServices(); + } } @Override diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 689c8f7e6e01..31ed8ba7dd23 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -10,6 +10,7 @@ import android.os.SystemClock; import android.test.AndroidTestCase; import android.test.RenamingDelegatingContext; import android.util.Log; +import android.util.Pair; import com.android.server.job.JobStore.JobSet; import com.android.server.job.controllers.JobStatus; @@ -63,7 +64,7 @@ public class JobStoreTest extends AndroidTestCase { Thread.sleep(IO_WAIT); // Manually load tasks from xml file. final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Didn't get expected number of persisted tasks.", 1, jobStatusSet.size()); final JobStatus loadedTaskStatus = jobStatusSet.getAllJobs().get(0); @@ -98,7 +99,7 @@ public class JobStoreTest extends AndroidTestCase { Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Incorrect # of persisted tasks.", 2, jobStatusSet.size()); Iterator<JobStatus> it = jobStatusSet.getAllJobs().iterator(); JobStatus loaded1 = it.next(); @@ -146,7 +147,7 @@ public class JobStoreTest extends AndroidTestCase { Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); assertTasksEqual(task, loaded.getJob()); @@ -164,7 +165,7 @@ public class JobStoreTest extends AndroidTestCase { Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); assertEquals("Source package not equal.", loaded.getSourcePackageName(), @@ -185,7 +186,7 @@ public class JobStoreTest extends AndroidTestCase { Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); assertEquals("Period not equal.", loaded.getJob().getIntervalMillis(), @@ -200,20 +201,23 @@ public class JobStoreTest extends AndroidTestCase { JobInfo.Builder b = new Builder(8, mComponent) .setPeriodic(TWO_HOURS, ONE_HOUR) .setPersisted(true); + final long rtcNow = System.currentTimeMillis(); final long invalidLateRuntimeElapsedMillis = SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex final long invalidEarlyRuntimeElapsedMillis = invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period). + final Pair<Long, Long> persistedExecutionTimesUTC = new Pair<>(rtcNow, rtcNow + ONE_HOUR); final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", 0 /* sourceUserId */, "someTag", invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis, - 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */); + 0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */, + persistedExecutionTimesUTC); mTaskStoreUnderTest.add(js); Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Incorrect # of persisted tasks.", 1, jobStatusSet.size()); JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); @@ -236,7 +240,7 @@ public class JobStoreTest extends AndroidTestCase { mTaskStoreUnderTest.add(js); Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); JobStatus loaded = jobStatusSet.getAllJobs().iterator().next(); assertEquals("Priority not correctly persisted.", 42, loaded.getPriority()); } @@ -257,7 +261,7 @@ public class JobStoreTest extends AndroidTestCase { mTaskStoreUnderTest.add(jsPersisted); Thread.sleep(IO_WAIT); final JobSet jobStatusSet = new JobSet(); - mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet); + mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true); assertEquals("Job count is incorrect.", 1, jobStatusSet.size()); JobStatus jobStatus = jobStatusSet.getAllJobs().iterator().next(); assertEquals("Wrong job persisted.", 43, jobStatus.getJobId()); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index afc0f67fe993..e2dfb29be561 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -23,10 +23,14 @@ import android.os.UserHandle; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import dalvik.system.DelegateLastClassLoader; +import dalvik.system.PathClassLoader; import dalvik.system.VMRuntime; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -48,6 +52,10 @@ import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; @RunWith(AndroidJUnit4.class) @SmallTest public class DexManagerTests { + private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); + private static final String DELEGATE_LAST_CLASS_LOADER_NAME = + DelegateLastClassLoader.class.getName(); + private DexManager mDexManager; private TestData mFooUser0; @@ -56,6 +64,9 @@ public class DexManagerTests { private TestData mInvalidIsa; private TestData mDoesNotExist; + private TestData mBarUser0UnsupportedClassLoader; + private TestData mBarUser0DelegateLastClassLoader; + private int mUser0; private int mUser1; @@ -68,12 +79,17 @@ public class DexManagerTests { String foo = "foo"; String bar = "bar"; - mFooUser0 = new TestData(foo, isa, mUser0); - mBarUser0 = new TestData(bar, isa, mUser0); - mBarUser1 = new TestData(bar, isa, mUser1); + mFooUser0 = new TestData(foo, isa, mUser0, PATH_CLASS_LOADER_NAME); + mBarUser0 = new TestData(bar, isa, mUser0, PATH_CLASS_LOADER_NAME); + mBarUser1 = new TestData(bar, isa, mUser1, PATH_CLASS_LOADER_NAME); mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); + mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0, + "unsupported.class_loader"); + mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, + DELEGATE_LAST_CLASS_LOADER_NAME); + mDexManager = new DexManager(null, null, null, null); // Foo and Bar are available to user0. @@ -373,8 +389,82 @@ public class DexManagerTests { assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); } + @Test + public void testNotifyUnsupportedClassLoader() { + List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); + notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); + assertNotNull(pui); + assertFalse(pui.isUsedByOtherApps()); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + // We expect that all the contexts are unsupported. + String[] expectedContexts = + Collections.nCopies(secondaries.size(), + PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); + assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, + /*isUsedByOtherApps*/false, mUser0, expectedContexts); + } + + @Test + public void testNotifyVariableClassLoader() { + // Record bar secondaries with the default PathClassLoader. + List<String> secondaries = mBarUser0.getSecondaryDexPaths(); + + notifyDexLoad(mBarUser0, secondaries, mUser0); + PackageUseInfo pui = getPackageUseInfo(mBarUser0); + assertNotNull(pui); + assertFalse(pui.isUsedByOtherApps()); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); + + // Record bar secondaries again with a different class loader. This will change the context. + notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); + + pui = getPackageUseInfo(mBarUser0); + assertNotNull(pui); + assertFalse(pui.isUsedByOtherApps()); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + // We expect that all the contexts to be changed to variable now. + String[] expectedContexts = + Collections.nCopies(secondaries.size(), + PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT).toArray(new String[0]); + assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, + expectedContexts); + } + + @Test + public void testNotifyUnsupportedClassLoaderDoesNotChange() { + List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); + notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); + assertNotNull(pui); + assertFalse(pui.isUsedByOtherApps()); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + // We expect that all the contexts are unsupported. + String[] expectedContexts = + Collections.nCopies(secondaries.size(), + PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); + assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, + /*isUsedByOtherApps*/false, mUser0, expectedContexts); + + // Record bar secondaries again with a different class loader. This will change the context. + // However, because the context was already marked as unsupported we should not chage it. + notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); + pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); + assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, + /*isUsedByOtherApps*/false, mUser0, expectedContexts); + + } + + private void assertSecondaryUse(TestData testData, PackageUseInfo pui, - List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { + List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, + String[] expectedContexts) { + assertNotNull(expectedContexts); + assertEquals(expectedContexts.length, secondaries.size()); + int index = 0; for (String dex : secondaries) { DexUseInfo dui = pui.getDexUseInfoMap().get(dex); assertNotNull(dui); @@ -382,11 +472,29 @@ public class DexManagerTests { assertEquals(ownerUserId, dui.getOwnerUserId()); assertEquals(1, dui.getLoaderIsas().size()); assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); + assertEquals(expectedContexts[index++], dui.getClassLoaderContext()); } } + private void assertSecondaryUse(TestData testData, PackageUseInfo pui, + List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { + String[] expectedContexts = DexoptUtils.processContextForDexLoad( + Arrays.asList(testData.mClassLoader), + Arrays.asList(String.join(File.pathSeparator, secondaries))); + assertSecondaryUse(testData, pui, secondaries, isUsedByOtherApps, ownerUserId, + expectedContexts); + } private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { - mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths, + // By default, assume a single class loader in the chain. + // This makes writing tests much easier. + List<String> classLoaders = Arrays.asList(testData.mClassLoader); + List<String> classPaths = Arrays.asList(String.join(File.pathSeparator, dexPaths)); + notifyDexLoad(testData, classLoaders, classPaths, loaderUserId); + } + + private void notifyDexLoad(TestData testData, List<String> classLoader, List<String> classPaths, + int loaderUserId) { + mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, classLoader, classPaths, testData.mLoaderIsa, loaderUserId); } @@ -416,10 +524,16 @@ public class DexManagerTests { private static class TestData { private final PackageInfo mPackageInfo; private final String mLoaderIsa; + private final String mClassLoader; - private TestData(String packageName, String loaderIsa, int userId) { + private TestData(String packageName, String loaderIsa, int userId, String classLoader) { mPackageInfo = getMockPackageInfo(packageName, userId); mLoaderIsa = loaderIsa; + mClassLoader = classLoader; + } + + private TestData(String packageName, String loaderIsa, int userId) { + this(packageName, loaderIsa, userId, PATH_CLASS_LOADER_NAME); } private String getPackageName() { diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 47918eab41c1..2c56a8263a8c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -17,6 +17,9 @@ package com.android.server.pm.dex; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import android.content.pm.ApplicationInfo; import android.support.test.filters.SmallTest; @@ -24,14 +27,21 @@ import android.support.test.runner.AndroidJUnit4; import android.util.SparseArray; import dalvik.system.DelegateLastClassLoader; +import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + @RunWith(AndroidJUnit4.class) @SmallTest public class DexoptUtilsTest { + private static final String DEX_CLASS_LOADER_NAME = DexClassLoader.class.getName(); private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); private static final String DELEGATE_LAST_CLASS_LOADER_NAME = DelegateLastClassLoader.class.getName(); @@ -57,7 +67,7 @@ public class DexoptUtilsTest { DELEGATE_LAST_CLASS_LOADER_NAME, DELEGATE_LAST_CLASS_LOADER_NAME, PATH_CLASS_LOADER_NAME, - PATH_CLASS_LOADER_NAME, + DEX_CLASS_LOADER_NAME, PATH_CLASS_LOADER_NAME, null}; // A null class loader name should default to PathClassLoader. if (addSplitDependencies) { @@ -210,4 +220,68 @@ public class DexoptUtilsTest { assertEquals(1, contexts.length); assertEquals("DLC[]", contexts[0]); } + + @Test + public void testProcessContextForDexLoad() { + List<String> classLoaders = Arrays.asList( + DELEGATE_LAST_CLASS_LOADER_NAME, + PATH_CLASS_LOADER_NAME, + PATH_CLASS_LOADER_NAME); + List<String> classPaths = Arrays.asList( + String.join(File.pathSeparator, "foo.dex", "bar.dex"), + String.join(File.pathSeparator, "parent1.dex"), + String.join(File.pathSeparator, "parent2.dex", "parent3.dex")); + String[] context = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); + assertNotNull(context); + assertEquals(2, context.length); + assertEquals("DLC[];PCL[parent1.dex];PCL[parent2.dex:parent3.dex]", context[0]); + assertEquals("DLC[foo.dex];PCL[parent1.dex];PCL[parent2.dex:parent3.dex]", context[1]); + } + + @Test + public void testProcessContextForDexLoadSingleElement() { + List<String> classLoaders = Arrays.asList(PATH_CLASS_LOADER_NAME); + List<String> classPaths = Arrays.asList( + String.join(File.pathSeparator, "foo.dex", "bar.dex", "zoo.dex")); + String[] context = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); + assertNotNull(context); + assertEquals(3, context.length); + assertEquals("PCL[]", context[0]); + assertEquals("PCL[foo.dex]", context[1]); + assertEquals("PCL[foo.dex:bar.dex]", context[2]); + } + + @Test + public void testProcessContextForDexLoadUnsupported() { + List<String> classLoaders = Arrays.asList( + DELEGATE_LAST_CLASS_LOADER_NAME, + "unsupported.class.loader"); + List<String> classPaths = Arrays.asList( + String.join(File.pathSeparator, "foo.dex", "bar.dex"), + String.join(File.pathSeparator, "parent1.dex")); + String[] context = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); + assertNull(context); + } + + @Test + public void testProcessContextForDexLoadIllegalCallEmptyList() { + boolean gotException = false; + try { + DexoptUtils.processContextForDexLoad(Collections.emptyList(), Collections.emptyList()); + } catch (IllegalArgumentException ignore) { + gotException = true; + } + assertTrue(gotException); + } + + @Test + public void testProcessContextForDexLoadIllegalCallDifferentSize() { + boolean gotException = false; + try { + DexoptUtils.processContextForDexLoad(Collections.emptyList(), Arrays.asList("a")); + } catch (IllegalArgumentException ignore) { + gotException = true; + } + assertTrue(gotException); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java index e1ef41e71c34..3fc12b473429 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java @@ -359,7 +359,7 @@ public class PackageDexUsageTests { public void testRecordDexFileUsersNotTheOwningPackage() { PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage(); Set<String> users = new HashSet<>(Arrays.asList( - new String[] {mFooBaseUser0.mPackageName,})); + new String[] {mFooBaseUser0.mPackageName})); Set<String> usersExtra = new HashSet<>(Arrays.asList( new String[] {"another.package.2", "another.package.3"})); @@ -375,6 +375,89 @@ public class PackageDexUsageTests { mFooSecondary1User0); } + @Test + public void testRecordClassLoaderContextVariableContext() { + // Record a secondary dex file. + assertTrue(record(mFooSecondary1User0)); + // Now update its context. + TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext( + "PCL[new_context.dex]"); + assertTrue(record(fooSecondary1User0NewContext)); + + // Not check that the context was switch to variable. + TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext( + PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT); + + assertPackageDexUsage(null, expectedContext); + writeAndReadBack(); + assertPackageDexUsage(null, expectedContext); + } + + @Test + public void testRecordClassLoaderContextUnsupportedContext() { + // Record a secondary dex file. + assertTrue(record(mFooSecondary1User0)); + // Now update its context. + TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext( + PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); + assertTrue(record(unsupportedContext)); + + assertPackageDexUsage(null, unsupportedContext); + writeAndReadBack(); + assertPackageDexUsage(null, unsupportedContext); + } + + @Test + public void testRecordClassLoaderContextTransitionFromUnknown() { + // Record a secondary dex file. + TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext( + PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT); + assertTrue(record(unknownContext)); + + assertPackageDexUsage(null, unknownContext); + writeAndReadBack(); + assertPackageDexUsage(null, unknownContext); + + // Now update the secondary dex record with a class loader context. This simulates the + // version 2 to version 3 upgrade. + + assertTrue(record(mFooSecondary1User0)); + + assertPackageDexUsage(null, mFooSecondary1User0); + writeAndReadBack(); + assertPackageDexUsage(null, mFooSecondary1User0); + } + + + @Test + public void testDexUsageClassLoaderContext() { + final boolean isUsedByOtherApps = false; + final int userId = 0; + PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId, + "valid_context", "arm"); + assertFalse(validContext.isUnknownClassLoaderContext()); + assertFalse(validContext.isUnsupportedClassLoaderContext()); + assertFalse(validContext.isVariableClassLoaderContext()); + + PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId, + PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm"); + assertFalse(unsupportedContext.isUnknownClassLoaderContext()); + assertTrue(unsupportedContext.isUnsupportedClassLoaderContext()); + assertFalse(unsupportedContext.isVariableClassLoaderContext()); + + PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId, + PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm"); + assertFalse(variableContext.isUnknownClassLoaderContext()); + assertFalse(variableContext.isUnsupportedClassLoaderContext()); + assertTrue(variableContext.isVariableClassLoaderContext()); + + PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId, + PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm"); + assertTrue(unknownContext.isUnknownClassLoaderContext()); + assertFalse(unknownContext.isUnsupportedClassLoaderContext()); + assertFalse(unknownContext.isVariableClassLoaderContext()); + } + private void assertPackageDexUsage(TestData primary, TestData... secondaries) { assertPackageDexUsage(mPackageDexUsage, null, primary, secondaries); } @@ -382,7 +465,7 @@ public class PackageDexUsageTests { private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, TestData... secondaries) { String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName; - boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps; + boolean primaryUsedByOtherApps = primary != null && primary.mUsedByOtherApps; PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName); // Check package use info @@ -406,13 +489,15 @@ public class PackageDexUsageTests { if (users != null) { assertEquals(dInfo.getLoadingPackages(), users); } + + assertEquals(testData.mClassLoaderContext, dInfo.getClassLoaderContext()); } } private boolean record(TestData testData) { return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile, testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps, - testData.mPrimaryOrSplit, testData.mUsedBy); + testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext); } private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) { @@ -420,7 +505,7 @@ public class PackageDexUsageTests { for (String user : users) { result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile, testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps, - testData.mPrimaryOrSplit, user); + testData.mPrimaryOrSplit, user, testData.mClassLoaderContext); } return result; } @@ -451,9 +536,16 @@ public class PackageDexUsageTests { private final boolean mUsedByOtherApps; private final boolean mPrimaryOrSplit; private final String mUsedBy; + private final String mClassLoaderContext; private TestData(String packageName, String dexFile, int ownerUserId, - String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy) { + String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy) { + this(packageName, dexFile, ownerUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, + usedBy, "DefaultClassLoaderContextFor_" + dexFile); + } + private TestData(String packageName, String dexFile, int ownerUserId, + String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy, + String classLoaderContext) { mPackageName = packageName; mDexFile = dexFile; mOwnerUserId = ownerUserId; @@ -461,7 +553,12 @@ public class PackageDexUsageTests { mUsedByOtherApps = isUsedByOtherApps; mPrimaryOrSplit = primaryOrSplit; mUsedBy = usedBy; + mClassLoaderContext = classLoaderContext; } + private TestData updateClassLoaderContext(String newContext) { + return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, mUsedByOtherApps, + mPrimaryOrSplit, mUsedBy, newContext); + } } } diff --git a/services/tests/servicestests/src/com/android/server/wm/AppBoundsTests.java b/services/tests/servicestests/src/com/android/server/wm/AppBoundsTests.java index 6c95bd514699..432cfc7a22ee 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppBoundsTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppBoundsTests.java @@ -60,6 +60,7 @@ public class AppBoundsTests extends WindowTestsBase { config2.appBounds = new Rect(1, 2, 2, 1); assertEquals(ActivityInfo.CONFIG_SCREEN_SIZE, config.diff(config2)); + assertEquals(0, config.diffPublicOnly(config2)); } /** diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 36083bf7a71e..b09601e698f9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -185,6 +185,11 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_UNSET, token.getOrientation()); // Can specify orientation if the current orientation candidate is orientation behind. assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation(SCREEN_ORIENTATION_BEHIND)); + + token.sendingToBottom = false; + token.setIsOnTop(true); + // Allow for token to provide orientation hidden if on top and not being sent to bottom. + assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index b83532cfa831..7ff1110e00f7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -89,6 +89,7 @@ public class WindowTestUtils { /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */ public static class TestAppWindowToken extends AppWindowToken { + boolean mOnTop = false; TestAppWindowToken(DisplayContent dc) { super(dc.mService, new IApplicationToken.Stub() {}, false, dc, true /* fillsParent */, @@ -125,6 +126,15 @@ public class WindowTestUtils { int positionInParent() { return getParent().mChildren.indexOf(this); } + + void setIsOnTop(boolean onTop) { + mOnTop = onTop; + } + + @Override + boolean isOnTop() { + return mOnTop; + } } /* Used so we can gain access to some protected members of the {@link WindowToken} class */ diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 184dd73381ec..774bf438995c 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -1153,8 +1153,7 @@ public class UsbDeviceManager { .usb_unsupported_audio_accessory_message); } - Notification notification = - new Notification.Builder(mContext, channel) + Notification.Builder builder = new Notification.Builder(mContext, channel) .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) .setWhen(0) .setOngoing(true) @@ -1166,8 +1165,15 @@ public class UsbDeviceManager { .setContentTitle(title) .setContentText(message) .setContentIntent(pi) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .build(); + .setVisibility(Notification.VISIBILITY_PUBLIC); + + if (titleRes + == com.android.internal.R.string + .usb_unsupported_audio_accessory_title) { + builder.setStyle(new Notification.BigTextStyle() + .bigText(message)); + } + Notification notification = builder.build(); mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 303a577767ad..d4a0ac4a0da3 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -123,21 +123,27 @@ public class UsbDescriptorParser { ByteStream stream = new ByteStream(descriptors); while (stream.available() > 0) { - UsbDescriptor descriptor = allocDescriptor(stream); + UsbDescriptor descriptor = null; + try { + descriptor = allocDescriptor(stream); + } catch (Exception ex) { + Log.e(TAG, "Exception allocating USB descriptor.", ex); + } + if (descriptor != null) { // Parse try { descriptor.parseRawDescriptors(stream); + + // Its OK to add the invalid descriptor as the postParse() + // routine will mark it as invalid. + mDescriptors.add(descriptor); + + // Clean up + descriptor.postParse(stream); } catch (Exception ex) { Log.e(TAG, "Exception parsing USB descriptors.", ex); } - - // Its OK to add the invalid descriptor as the postParse() - // routine will mark it as invalid. - mDescriptors.add(descriptor); - - // Clean up - descriptor.postParse(stream); } } } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index f8485ef3af3a..4dc78627ef91 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -345,7 +345,8 @@ public class WifiInfo implements Parcelable { * Returns the service set identifier (SSID) of the current 802.11 network. * If the SSID can be decoded as UTF-8, it will be returned surrounded by double * quotation marks. Otherwise, it is returned as a string of hex digits. The - * SSID may be <unknown ssid> if there is no network currently connected. + * SSID may be <unknown ssid> if there is no network currently connected, + * or if the caller has insufficient permissions to access the SSID. * @return the SSID */ public String getSSID() { diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 598360cc9ef0..c499edcd3e44 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1633,6 +1633,12 @@ public class WifiManager { /** * Return dynamic information about the current Wi-Fi connection, if any is active. + * <p> + * In the connected state, access to the SSID and BSSID requires + * the same permissions as {@link #getScanResults}. If such access is not allowed, + * {@link WifiInfo#getSSID} will return {@code "<unknown ssid>"} and + * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}. + * * @return the Wi-Fi information, contained in {@link WifiInfo}. */ public WifiInfo getConnectionInfo() { @@ -2330,7 +2336,7 @@ public class WifiManager { /** WPS start succeeded */ public abstract void onStarted(String pin); - /** WPS operation completed succesfully */ + /** WPS operation completed successfully */ public abstract void onSucceeded(); /** @@ -3213,7 +3219,7 @@ public class WifiManager { * Normally the Wifi stack filters out packets not explicitly * addressed to this device. Acquring a MulticastLock will * cause the stack to receive packets addressed to multicast - * addresses. Processing these extra packets can cause a noticable + * addresses. Processing these extra packets can cause a noticeable * battery drain and should be disabled when not needed. */ public class MulticastLock { |