summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt10
-rw-r--r--api/system-current.txt10
-rw-r--r--api/test-current.txt10
-rw-r--r--core/java/android/app/RecoverableSecurityException.java70
-rw-r--r--core/java/android/content/pm/ActivityInfo.java1
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java44
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl2
-rw-r--r--core/java/android/os/storage/StorageManager.java145
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/WindowManager.java34
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java7
-rw-r--r--core/java/android/widget/PopupWindow.java5
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl5
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl4
-rw-r--r--core/java/com/android/internal/view/InputMethodClient.java63
-rw-r--r--core/java/com/android/internal/widget/SwipeDismissLayout.java36
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java8
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java55
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/MockStorageManager.java10
-rw-r--r--tools/aapt2/link/Link.cpp5
-rw-r--r--tools/aapt2/split/TableSplitter.cpp39
-rw-r--r--tools/aapt2/split/TableSplitter.h8
-rw-r--r--tools/aapt2/split/TableSplitter_test.cpp47
-rw-r--r--tools/aapt2/strip/Strip.cpp13
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java3
27 files changed, 488 insertions, 167 deletions
diff --git a/api/current.txt b/api/current.txt
index 302b99a8ff83..e0d895ed85cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15,6 +15,7 @@ package android {
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+ field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -5674,10 +5675,9 @@ package android.app {
}
public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
method public int describeContents();
- method public android.app.PendingIntent getUserAction();
- method public java.lang.CharSequence getUserActionTitle();
+ method public android.app.RemoteAction getUserAction();
method public java.lang.CharSequence getUserMessage();
method public void showAsDialog(android.app.Activity);
method public void showAsNotification(android.content.Context);
@@ -31212,6 +31212,9 @@ package android.os.storage {
}
public class StorageManager {
+ method public void allocateBytes(java.io.File, long, int) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
+ method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
method public long getCacheQuotaBytes();
method public long getCacheSizeBytes();
method public long getExternalCacheQuotaBytes();
@@ -31230,6 +31233,7 @@ package android.os.storage {
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
+ field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
public final class StorageVolume implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 486944008408..a5f30819e353 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -23,6 +23,7 @@ package android {
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+ field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
@@ -5870,10 +5871,9 @@ package android.app {
}
public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
method public int describeContents();
- method public android.app.PendingIntent getUserAction();
- method public java.lang.CharSequence getUserActionTitle();
+ method public android.app.RemoteAction getUserAction();
method public java.lang.CharSequence getUserMessage();
method public void showAsDialog(android.app.Activity);
method public void showAsNotification(android.content.Context);
@@ -34082,6 +34082,9 @@ package android.os.storage {
}
public class StorageManager {
+ method public void allocateBytes(java.io.File, long, int) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
+ method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
method public long getCacheQuotaBytes();
method public long getCacheSizeBytes();
method public long getExternalCacheQuotaBytes();
@@ -34100,6 +34103,7 @@ package android.os.storage {
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
+ field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
public final class StorageVolume implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 7c06b9e67f2c..a983cf540b64 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -15,6 +15,7 @@ package android {
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+ field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -5685,10 +5686,9 @@ package android.app {
}
public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
- ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
method public int describeContents();
- method public android.app.PendingIntent getUserAction();
- method public java.lang.CharSequence getUserActionTitle();
+ method public android.app.RemoteAction getUserAction();
method public java.lang.CharSequence getUserMessage();
method public void showAsDialog(android.app.Activity);
method public void showAsNotification(android.content.Context);
@@ -31327,6 +31327,9 @@ package android.os.storage {
}
public class StorageManager {
+ method public void allocateBytes(java.io.File, long, int) throws java.io.IOException;
+ method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
+ method public long getAllocatableBytes(java.io.File, int) throws java.io.IOException;
method public long getCacheQuotaBytes();
method public long getCacheSizeBytes();
method public long getExternalCacheQuotaBytes();
@@ -31345,6 +31348,7 @@ package android.os.storage {
method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
+ field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
public final class StorageVolume implements android.os.Parcelable {
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
index 1f015a607be8..540d1cda1edd 100644
--- a/core/java/android/app/RecoverableSecurityException.java
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -17,6 +17,8 @@
package android.app;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -40,13 +42,12 @@ public final class RecoverableSecurityException extends SecurityException implem
private static final String TAG = "RecoverableSecurityException";
private final CharSequence mUserMessage;
- private final CharSequence mUserActionTitle;
- private final PendingIntent mUserAction;
+ private final RemoteAction mUserAction;
/** {@hide} */
public RecoverableSecurityException(Parcel in) {
- this(new SecurityException(in.readString()), in.readCharSequence(), in.readCharSequence(),
- PendingIntent.CREATOR.createFromParcel(in));
+ this(new SecurityException(in.readString()), in.readCharSequence(),
+ RemoteAction.CREATOR.createFromParcel(in));
}
/**
@@ -56,26 +57,35 @@ public final class RecoverableSecurityException extends SecurityException implem
* audiences.
* @param userMessage short message describing the issue for end user
* audiences, which may be shown in a notification or dialog.
- * This should be less than 64 characters. For example: <em>PIN
- * required to access Document.pdf</em>
- * @param userActionTitle short title describing the primary action. This
- * should be less than 24 characters. For example: <em>Enter
- * PIN</em>
- * @param userAction primary action that will initiate the recovery. This
- * must launch an activity that is expected to set
+ * This should be localized and less than 64 characters. For
+ * example: <em>PIN required to access Document.pdf</em>
+ * @param userAction primary action that will initiate the recovery. The
+ * title should be localized and less than 24 characters. For
+ * example: <em>Enter PIN</em>. This action must launch an
+ * activity that is expected to set
* {@link Activity#setResult(int)} before finishing to
* communicate the final status of the recovery. For example,
* apps that observe {@link Activity#RESULT_OK} may choose to
* immediately retry their operation.
*/
public RecoverableSecurityException(Throwable cause, CharSequence userMessage,
- CharSequence userActionTitle, PendingIntent userAction) {
+ RemoteAction userAction) {
super(cause.getMessage());
mUserMessage = Preconditions.checkNotNull(userMessage);
- mUserActionTitle = Preconditions.checkNotNull(userActionTitle);
mUserAction = Preconditions.checkNotNull(userAction);
}
+ /** {@hide} */
+ @Deprecated
+ public RecoverableSecurityException(Throwable cause, CharSequence userMessage,
+ CharSequence userActionTitle, PendingIntent userAction) {
+ this(cause, userMessage,
+ new RemoteAction(
+ Icon.createWithResource("android",
+ com.android.internal.R.drawable.ic_restart),
+ userActionTitle, userActionTitle, userAction));
+ }
+
/**
* Return short message describing the issue for end user audiences, which
* may be shown in a notification or dialog.
@@ -85,16 +95,9 @@ public final class RecoverableSecurityException extends SecurityException implem
}
/**
- * Return short title describing the primary action.
- */
- public CharSequence getUserActionTitle() {
- return mUserActionTitle;
- }
-
- /**
* Return primary action that will initiate the recovery.
*/
- public PendingIntent getUserAction() {
+ public RemoteAction getUserAction() {
return mUserAction;
}
@@ -113,15 +116,21 @@ public final class RecoverableSecurityException extends SecurityException implem
* remote UID; notifications from older exceptions will always be replaced.
*/
public void showAsNotification(Context context) {
- final Notification.Builder builder = new Notification.Builder(context)
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+
+ // Create a channel per-sender, since we don't want one poorly behaved
+ // remote app to cause all of our notifications to be blocked
+ final String tag = TAG + "_" + mUserAction.getActionIntent().getCreatorUid();
+ nm.createNotificationChannel(new NotificationChannel(tag, TAG,
+ NotificationManager.IMPORTANCE_DEFAULT));
+
+ final Notification.Builder builder = new Notification.Builder(context, tag)
.setSmallIcon(com.android.internal.R.drawable.ic_print_error)
- .setContentTitle(mUserActionTitle)
+ .setContentTitle(mUserAction.getTitle())
.setContentText(mUserMessage)
- .setContentIntent(mUserAction)
+ .setContentIntent(mUserAction.getActionIntent())
.setCategory(Notification.CATEGORY_ERROR);
-
- final NotificationManager nm = context.getSystemService(NotificationManager.class);
- nm.notify(TAG, mUserAction.getCreatorUid(), builder.build());
+ nm.notify(tag, 0, builder.build());
}
/**
@@ -144,7 +153,7 @@ public final class RecoverableSecurityException extends SecurityException implem
args.putParcelable(TAG, this);
dialog.setArguments(args);
- final String tag = TAG + "_" + mUserAction.getCreatorUid();
+ final String tag = TAG + "_" + mUserAction.getActionIntent().getCreatorUid();
final FragmentManager fm = activity.getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
final Fragment old = fm.findFragmentByTag(tag);
@@ -162,9 +171,9 @@ public final class RecoverableSecurityException extends SecurityException implem
final RecoverableSecurityException e = getArguments().getParcelable(TAG);
return new AlertDialog.Builder(getActivity())
.setMessage(e.mUserMessage)
- .setPositiveButton(e.mUserActionTitle, (dialog, which) -> {
+ .setPositiveButton(e.mUserAction.getTitle(), (dialog, which) -> {
try {
- e.mUserAction.send();
+ e.mUserAction.getActionIntent().send();
} catch (PendingIntent.CanceledException ignored) {
}
})
@@ -182,7 +191,6 @@ public final class RecoverableSecurityException extends SecurityException implem
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getMessage());
dest.writeCharSequence(mUserMessage);
- dest.writeCharSequence(mUserActionTitle);
mUserAction.writeToParcel(dest, flags);
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 9a8eff098c1e..48c52d5fc4e8 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -824,6 +824,7 @@ public class ActivityInfo extends ComponentInfo
* WindowManager.LayoutParams.softInputMode}. If 0 (unspecified),
* the mode from the theme will be used.
*/
+ @android.view.WindowManager.LayoutParams.SoftInputModeFlags
public int softInputMode;
/**
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 167d5a09a2dc..bc407504a20d 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -61,7 +61,6 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final int DO_SET_INPUT_CONTEXT = 20;
private static final int DO_UNSET_INPUT_CONTEXT = 30;
private static final int DO_START_INPUT = 32;
- private static final int DO_RESTART_INPUT = 34;
private static final int DO_CREATE_SESSION = 40;
private static final int DO_SET_SESSION_ENABLED = 45;
private static final int DO_REVOKE_SESSION = 50;
@@ -164,26 +163,19 @@ class IInputMethodWrapper extends IInputMethod.Stub
inputMethod.unbindInput();
return;
case DO_START_INPUT: {
- SomeArgs args = (SomeArgs)msg.obj;
- int missingMethods = msg.arg1;
- IInputContext inputContext = (IInputContext)args.arg1;
- InputConnection ic = inputContext != null
- ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
- EditorInfo info = (EditorInfo)args.arg2;
- info.makeCompatible(mTargetSdkVersion);
- inputMethod.startInput(ic, info);
- args.recycle();
- return;
- }
- case DO_RESTART_INPUT: {
- SomeArgs args = (SomeArgs)msg.obj;
- int missingMethods = msg.arg1;
- IInputContext inputContext = (IInputContext)args.arg1;
- InputConnection ic = inputContext != null
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final int missingMethods = msg.arg1;
+ final boolean restarting = msg.arg2 != 0;
+ final IInputContext inputContext = (IInputContext) args.arg1;
+ final EditorInfo info = (EditorInfo) args.arg2;
+ final InputConnection ic = inputContext != null
? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
- EditorInfo info = (EditorInfo)args.arg2;
info.makeCompatible(mTargetSdkVersion);
- inputMethod.restartInput(ic, info);
+ if (restarting) {
+ inputMethod.restartInput(ic, info);
+ } else {
+ inputMethod.startInput(ic, info);
+ }
args.recycle();
return;
}
@@ -265,17 +257,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
@Override
public void startInput(IInputContext inputContext,
@InputConnectionInspector.MissingMethodFlags final int missingMethods,
- EditorInfo attribute) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_START_INPUT,
- missingMethods, inputContext, attribute));
- }
-
- @Override
- public void restartInput(IInputContext inputContext,
- @InputConnectionInspector.MissingMethodFlags final int missingMethods,
- EditorInfo attribute) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_RESTART_INPUT,
- missingMethods, inputContext, attribute));
+ EditorInfo attribute, boolean restarting) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageIIOO(DO_START_INPUT,
+ missingMethods, restarting ? 1 : 0, inputContext, attribute));
}
@Override
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 35a266b7ab41..9e35bf68d78c 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -293,4 +293,6 @@ interface IStorageManager {
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
long getCacheSizeBytes(String volumeUuid, int uid) = 76;
+ long getAllocatableBytes(String path, int flags) = 77;
+ void allocateBytes(String path, long bytes, int flags) = 78;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 626d6f4698ca..2a3c03d1f84f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -18,8 +18,10 @@ package android.os.storage;
import static android.net.TrafficStats.MB_IN_BYTES;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.app.ActivityThread;
import android.content.ContentResolver;
@@ -34,6 +36,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelableException;
import android.os.ProxyFileDescriptorCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -60,10 +63,13 @@ import com.android.internal.util.Preconditions;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -1424,10 +1430,7 @@ public class StorageManager {
* as a single unit.
* </p>
*
- * @see #getCacheQuotaBytes()
* @see #getCacheSizeBytes()
- * @see #getExternalCacheQuotaBytes()
- * @see #getExternalCacheSizeBytes()
*/
public long getCacheQuotaBytes() {
try {
@@ -1453,9 +1456,6 @@ public class StorageManager {
* </p>
*
* @see #getCacheQuotaBytes()
- * @see #getCacheSizeBytes()
- * @see #getExternalCacheQuotaBytes()
- * @see #getExternalCacheSizeBytes()
*/
public long getCacheSizeBytes() {
try {
@@ -1520,6 +1520,139 @@ public class StorageManager {
}
}
+ /**
+ * Flag indicating that a disk space allocation request should operate in an
+ * aggressive mode. This flag should only be rarely used in situations that
+ * are critical to system health or security.
+ * <p>
+ * When set, the system is more aggressive about the data that it considers
+ * for possible deletion when allocating disk space.
+ * <p class="note">
+ * Note: your app must hold the
+ * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
+ * this flag to take effect.
+ * </p>
+ *
+ * @see #getAllocatableBytes(File, int)
+ * @see #allocateBytes(File, long, int)
+ * @see #allocateBytes(FileDescriptor, long, int)
+ */
+ @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
+ public static final int FLAG_ALLOCATE_AGGRESSIVE = 1;
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ FLAG_ALLOCATE_AGGRESSIVE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AllocateFlags {}
+
+ /**
+ * Return the maximum number of new bytes that your app can allocate for
+ * itself using {@link #allocateBytes(File, long, int)} at the given path.
+ * This value is typically larger than {@link File#getUsableSpace()}, since
+ * the system may automatically delete cached files to satisfy your request.
+ * <p>
+ * This method is best used as a pre-flight check, such as deciding if there
+ * is enough space to store an entire music album before you allocate space
+ * for each audio file in the album. Attempts to allocate disk space beyond
+ * this value will fail.
+ * <p class="note">
+ * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+ * then allocatable space for all packages in your shared UID is tracked
+ * together as a single unit.
+ * </p>
+ *
+ * @param file the directory where you're considering allocating disk space,
+ * since allocatable space can vary widely depending on the
+ * underlying storage device.
+ * @param flags to apply to the request.
+ * @return the maximum number of new bytes that the calling app can allocate
+ * using {@link #allocateBytes(File, long, int)}.
+ */
+ public long getAllocatableBytes(File file, @AllocateFlags int flags) throws IOException {
+ try {
+ return mStorageManager.getAllocatableBytes(file.getAbsolutePath(), flags);
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allocate the requested number of bytes for your application to use at the
+ * given path. This will cause the system to delete any cached files
+ * necessary to satisfy your request.
+ * <p>
+ * Attempts to allocate disk space beyond the value returned by
+ * {@link #getAllocatableBytes(File, int)} will fail.
+ * <p>
+ * Since multiple apps can be running simultaneously, this method may be
+ * subject to race conditions. If possible, consider using
+ * {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee
+ * that bytes are allocated to an opened file.
+ *
+ * @param file the directory where you'd like to allocate disk space.
+ * @param bytes the number of bytes to allocate.
+ * @param flags to apply to the request.
+ * @see #getAllocatableBytes(File, int)
+ */
+ public void allocateBytes(File file, long bytes, @AllocateFlags int flags) throws IOException {
+ try {
+ mStorageManager.allocateBytes(file.getAbsolutePath(), bytes, flags);
+ } catch (ParcelableException e) {
+ e.maybeRethrow(IOException.class);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Allocate the requested number of bytes for your application to use at the
+ * given path. This will cause the system to delete any cached files
+ * necessary to satisfy your request.
+ * <p>
+ * Attempts to allocate disk space beyond the value returned by
+ * {@link #getAllocatableBytes(File, int)} will fail.
+ * <p>
+ * This method guarantees that bytes are allocated to the opened file,
+ * otherwise it will throw if fast allocation not possible. Fast allocation
+ * is typically only supported in private app data directories, and on
+ * shared/external storage devices which are emulated.
+ *
+ * @param fd the directory where you'd like to allocate disk space.
+ * @param bytes the number of bytes to allocate.
+ * @param flags to apply to the request.
+ * @see #getAllocatableBytes(File, int)
+ * @see Environment#isExternalStorageEmulated(File)
+ */
+ public void allocateBytes(FileDescriptor fd, long bytes, @AllocateFlags int flags)
+ throws IOException {
+ final File file;
+ try {
+ file = new File(Os.readlink("/proc/self/fd/" + fd.getInt$()));
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ for (int i = 0; i < 3; i++) {
+ allocateBytes(file, bytes, flags);
+
+ try {
+ Os.posix_fallocate(fd, 0, bytes);
+ } catch (ErrnoException e) {
+ if (e.errno == OsConstants.ENOSPC) {
+ Log.w(TAG, "Odd, not enough space; let's try again?");
+ continue;
+ }
+ throw e.rethrowAsIOException();
+ }
+ }
+ throw new IOException(
+ "Well this is embarassing; we can't allocate " + bytes + " for " + file);
+ }
+
private static final String XATTR_ATOMIC = "user.atomic";
private static final String XATTR_TOMBSTONE = "user.tombstone";
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bdc3e7f468c9..cc4c5c154bcf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -73,6 +73,7 @@ import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
+import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
@@ -334,6 +335,7 @@ public final class ViewRootImpl implements ViewParent,
final Configuration mPendingConfiguration = new Configuration();
boolean mScrollMayChange;
+ @SoftInputModeFlags
int mSoftInputMode;
WeakReference<View> mLastScrolledFocus;
int mScrollY;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5a640faf08d3..051f56f7152f 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.KeyguardManager;
@@ -30,6 +31,8 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Objects;
@@ -1540,24 +1543,45 @@ public interface WindowManager extends ViewManager {
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
/**
+ * An internal annotation for flags that can be specified to {@link #softInputMode}.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ SOFT_INPUT_STATE_UNSPECIFIED,
+ SOFT_INPUT_STATE_UNCHANGED,
+ SOFT_INPUT_STATE_HIDDEN,
+ SOFT_INPUT_STATE_ALWAYS_HIDDEN,
+ SOFT_INPUT_STATE_VISIBLE,
+ SOFT_INPUT_STATE_ALWAYS_VISIBLE,
+ SOFT_INPUT_ADJUST_UNSPECIFIED,
+ SOFT_INPUT_ADJUST_RESIZE,
+ SOFT_INPUT_ADJUST_PAN,
+ SOFT_INPUT_ADJUST_NOTHING,
+ SOFT_INPUT_IS_FORWARD_NAVIGATION,
+ })
+ public @interface SoftInputModeFlags {}
+
+ /**
* Desired operating mode for any soft input area. May be any combination
* of:
*
* <ul>
* <li> One of the visibility states
* {@link #SOFT_INPUT_STATE_UNSPECIFIED}, {@link #SOFT_INPUT_STATE_UNCHANGED},
- * {@link #SOFT_INPUT_STATE_HIDDEN}, {@link #SOFT_INPUT_STATE_ALWAYS_VISIBLE}, or
- * {@link #SOFT_INPUT_STATE_VISIBLE}.
+ * {@link #SOFT_INPUT_STATE_HIDDEN}, {@link #SOFT_INPUT_STATE_ALWAYS_HIDDEN},
+ * {@link #SOFT_INPUT_STATE_VISIBLE}, or {@link #SOFT_INPUT_STATE_ALWAYS_VISIBLE}.
* <li> One of the adjustment options
- * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED},
- * {@link #SOFT_INPUT_ADJUST_RESIZE}, or
- * {@link #SOFT_INPUT_ADJUST_PAN}.
+ * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED}, {@link #SOFT_INPUT_ADJUST_RESIZE},
+ * {@link #SOFT_INPUT_ADJUST_PAN}, or {@link #SOFT_INPUT_ADJUST_NOTHING}.
* </ul>
*
*
* <p>This flag can be controlled in your theme through the
* {@link android.R.attr#windowSoftInputMode} attribute.</p>
*/
+ @SoftInputModeFlags
public int softInputMode;
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 13abe7c6471d..1f76d28fab05 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -47,6 +47,7 @@ import android.view.InputEventSender;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.os.SomeArgs;
@@ -1490,12 +1491,12 @@ public final class InputMethodManager {
* Called by ViewAncestor when its window gets input focus.
* @hide
*/
- public void onPostWindowFocus(View rootView, View focusedView, int softInputMode,
- boolean first, int windowFlags) {
+ public void onPostWindowFocus(View rootView, View focusedView,
+ @SoftInputModeFlags int softInputMode, boolean first, int windowFlags) {
boolean forceNewFocus = false;
synchronized (mH) {
if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
- + " softInputMode=" + softInputMode
+ + " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode)
+ " first=" + first + " flags=#"
+ Integer.toHexString(windowFlags));
if (mHasBeenInactive) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 989927e0c22d..1436bdb3cbd9 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -54,6 +54,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import com.android.internal.R;
@@ -162,6 +163,7 @@ public class PopupWindow {
private boolean mFocusable;
private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE;
+ @SoftInputModeFlags
private int mSoftInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
private boolean mTouchable = true;
private boolean mOutsideTouchable = false;
@@ -724,7 +726,7 @@ public class PopupWindow {
* @see android.view.WindowManager.LayoutParams#softInputMode
* @see #getSoftInputMode()
*/
- public void setSoftInputMode(int mode) {
+ public void setSoftInputMode(@SoftInputModeFlags int mode) {
mSoftInputMode = mode;
}
@@ -734,6 +736,7 @@ public class PopupWindow {
* @see #setSoftInputMode(int)
* @see android.view.WindowManager.LayoutParams#softInputMode
*/
+ @SoftInputModeFlags
public int getSoftInputMode() {
return mSoftInputMode;
}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index 6ab1ec797a22..9870612dfac5 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -38,9 +38,8 @@ oneway interface IInputMethod {
void unbindInput();
- void startInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
-
- void restartInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute);
+ void startInput(in IInputContext inputContext, int missingMethods, in EditorInfo attribute,
+ boolean restarting);
void createSession(in InputChannel channel, IInputSessionCallback callback);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 2279a6706524..437764562b83 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -58,8 +58,8 @@ interface IInputMethodManager {
InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ int startInputReason,
in IInputMethodClient client, in IBinder windowToken, int controlFlags,
- int softInputMode, int windowFlags, in EditorInfo attribute,
- IInputContext inputContext,
+ /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
+ int windowFlags, in EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags);
void showInputMethodPickerFromClient(in IInputMethodClient client,
diff --git a/core/java/com/android/internal/view/InputMethodClient.java b/core/java/com/android/internal/view/InputMethodClient.java
index cea030a3d489..bbd33a258e18 100644
--- a/core/java/com/android/internal/view/InputMethodClient.java
+++ b/core/java/com/android/internal/view/InputMethodClient.java
@@ -17,6 +17,8 @@
package com.android.internal.view;
import android.annotation.IntDef;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import java.lang.annotation.Retention;
@@ -103,4 +105,65 @@ public final class InputMethodClient {
return "Unknown=" + reason;
}
}
+
+ public static String softInputModeToString(@SoftInputModeFlags final int softInputMode) {
+ final StringBuilder sb = new StringBuilder();
+ final int state = softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE;
+ final int adjust = softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST;
+ final boolean isForwardNav =
+ (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0;
+
+ switch (state) {
+ case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+ sb.append("STATE_UNSPECIFIED");
+ break;
+ case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+ sb.append("STATE_UNCHANGED");
+ break;
+ case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+ sb.append("STATE_HIDDEN");
+ break;
+ case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+ sb.append("STATE_ALWAYS_HIDDEN");
+ break;
+ case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+ sb.append("STATE_VISIBLE");
+ break;
+ case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+ sb.append("STATE_ALWAYS_VISIBLE");
+ break;
+ default:
+ sb.append("STATE_UNKNOWN(");
+ sb.append(state);
+ sb.append(")");
+ break;
+ }
+
+ switch (adjust) {
+ case LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED:
+ sb.append("|ADJUST_UNSPECIFIED");
+ break;
+ case LayoutParams.SOFT_INPUT_ADJUST_RESIZE:
+ sb.append("|ADJUST_RESIZE");
+ break;
+ case LayoutParams.SOFT_INPUT_ADJUST_PAN:
+ sb.append("|ADJUST_PAN");
+ break;
+ case LayoutParams.SOFT_INPUT_ADJUST_NOTHING:
+ sb.append("|ADJUST_NOTHING");
+ break;
+ default:
+ sb.append("|ADJUST_UNKNOWN(");
+ sb.append(adjust);
+ sb.append(")");
+ break;
+ }
+
+ if (isForwardNav) {
+ // This is a special bit that is set by the system only during the window navigation.
+ sb.append("|IS_FORWARD_NAVIGATION");
+ }
+
+ return sb.toString();
+ }
}
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 2a5957ce0ca2..261fa4327494 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -43,7 +43,8 @@ import android.widget.FrameLayout;
public class SwipeDismissLayout extends FrameLayout {
private static final String TAG = "SwipeDismissLayout";
- private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+ private static final float MAX_DIST_THRESHOLD = .33f;
+ private static final float MIN_DIST_THRESHOLD = .1f;
public interface OnDismissedListener {
void onDismissed(SwipeDismissLayout layout);
@@ -73,6 +74,7 @@ public class SwipeDismissLayout extends FrameLayout {
private int mActiveTouchId;
private float mDownX;
private float mDownY;
+ private float mLastX;
private boolean mSwiping;
private boolean mDismissed;
private boolean mDiscardIntercept;
@@ -105,7 +107,6 @@ public class SwipeDismissLayout extends FrameLayout {
};
private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- private float mLastX;
private boolean mDismissable = true;
@@ -174,7 +175,7 @@ public class SwipeDismissLayout extends FrameLayout {
mDownX = ev.getRawX();
mDownY = ev.getRawY();
mActiveTouchId = ev.getPointerId(0);
- mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker = VelocityTracker.obtain("int1");
mVelocityTracker.addMovement(ev);
break;
@@ -238,7 +239,10 @@ public class SwipeDismissLayout extends FrameLayout {
updateDismiss(ev);
if (mDismissed) {
mDismissAnimator.animateDismissal(ev.getRawX() - mDownX);
- } else if (mSwiping) {
+ } else if (mSwiping
+ // Only trigger animation if we had a MOVE event that would shift the
+ // underlying view, otherwise the animation would be janky.
+ && mLastX != Integer.MIN_VALUE) {
mDismissAnimator.animateRecovery(ev.getRawX() - mDownX);
}
resetMembers();
@@ -298,6 +302,7 @@ public class SwipeDismissLayout extends FrameLayout {
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
+ mLastX = Integer.MIN_VALUE;
mDownY = 0;
mSwiping = false;
mDismissed = false;
@@ -329,19 +334,32 @@ public class SwipeDismissLayout extends FrameLayout {
private void updateDismiss(MotionEvent ev) {
float deltaX = ev.getRawX() - mDownX;
- mVelocityTracker.addMovement(ev);
+ // Don't add the motion event as an UP event would clear the velocity tracker
mVelocityTracker.computeCurrentVelocity(1000);
+ float xVelocity = mVelocityTracker.getXVelocity();
+ if (mLastX == Integer.MIN_VALUE) {
+ // If there's no changes to mLastX, we have only one point of data, and therefore no
+ // velocity. Estimate velocity from just the up and down event in that case.
+ xVelocity = deltaX / ((ev.getEventTime() - ev.getDownTime()) / 1000);
+ }
if (!mDismissed) {
- if ((deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
- ev.getRawX() >= mLastX)
- || mVelocityTracker.getXVelocity() >= mMinFlingVelocity) {
+ // Adjust the distance threshold linearly between the min and max threshold based on the
+ // x-velocity scaled with the the fling threshold speed
+ float distanceThreshold = getWidth() * Math.max(
+ Math.min((MIN_DIST_THRESHOLD - MAX_DIST_THRESHOLD)
+ * xVelocity / mMinFlingVelocity // scale x-velocity with fling velocity
+ + MAX_DIST_THRESHOLD, // offset to start at max threshold
+ MAX_DIST_THRESHOLD), // cap at max threshold
+ MIN_DIST_THRESHOLD); // bottom out at min threshold
+ if ((deltaX > distanceThreshold && ev.getRawX() >= mLastX)
+ || xVelocity >= mMinFlingVelocity) {
mDismissed = true;
}
}
// Check if the user tried to undo this.
if (mDismissed && mSwiping) {
// Check if the user's finger is actually flinging back to left
- if (mVelocityTracker.getXVelocity() < -mMinFlingVelocity) {
+ if (xVelocity < -mMinFlingVelocity) {
mDismissed = false;
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5b5e61e6ebdc..cd02fbbedb7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1650,6 +1650,12 @@
<permission android:name="android.permission.CACHE_CONTENT"
android:protectionLevel="signature" />
+ <!-- Allows an application to aggressively allocate disk space.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.ALLOCATE_AGGRESSIVE"
+ android:protectionLevel="signature|privileged" />
+
<!-- ================================== -->
<!-- Permissions for screenlock -->
<!-- ================================== -->
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index ff934ef18677..4254a0ba200a 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -217,9 +217,6 @@ public class WallpaperBackupAgent extends BackupAgent {
final int sysWhich = FLAG_SYSTEM | (lockImageStage.exists() ? 0 : FLAG_LOCK);
try {
- // First off, revert to the factory state
- mWm.clear(FLAG_SYSTEM | FLAG_LOCK);
-
// It is valid for the imagery to be absent; it means that we were not permitted
// to back up the original image on the source device, or there was no user-supplied
// wallpaper image present.
@@ -233,6 +230,11 @@ public class WallpaperBackupAgent extends BackupAgent {
Slog.i(TAG, "Using wallpaper service " + wpService);
}
mWm.setWallpaperComponent(wpService, UserHandle.USER_SYSTEM);
+ if (!lockImageStage.exists()) {
+ // We have a live wallpaper and no static lock image,
+ // allow live wallpaper to show "through" on lock screen.
+ mWm.clear(FLAG_LOCK);
+ }
} else {
if (DEBUG) {
Slog.v(TAG, "Can't use wallpaper service " + wpService);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 2b3d8d4e1fb1..b7a1f8b34277 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -175,7 +175,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_START_INPUT = 2000;
- static final int MSG_RESTART_INPUT = 2010;
static final int MSG_UNBIND_CLIENT = 3000;
static final int MSG_BIND_CLIENT = 3010;
@@ -348,6 +347,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
IBinder mCurFocusedWindow;
/**
+ * {@link WindowManager.LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
+ *
+ * @see #mCurFocusedWindow
+ */
+ int mCurFocusedWindowSoftInputMode;
+
+ /**
* The client by which {@link #mCurFocusedWindow} was reported. Used only for debugging.
*/
ClientState mCurFocusedWindowClient;
@@ -1340,15 +1346,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mBoundToMethod = true;
}
final SessionState session = mCurClient.curSession;
- if (initial) {
- executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
- MSG_START_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
- mCurAttribute));
- } else {
- executeOrSendMessage(session.method, mCaller.obtainMessageIOOO(
- MSG_RESTART_INPUT, mCurInputContextMissingMethods, session, mCurInputContext,
- mCurAttribute));
- }
+ executeOrSendMessage(session.method, mCaller.obtainMessageIIOOO(
+ MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
+ session, mCurInputContext, mCurAttribute));
if (mShowRequested) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(getAppShowFlags(), null);
@@ -2271,7 +2271,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private InputBindResult windowGainedFocus(
/* @InputMethodClient.StartInputReason */ final int startInputReason,
- IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
+ IInputMethodClient client, IBinder windowToken, int controlFlags,
+ /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.missingMethods */ final int missingMethods) {
// Needs to check the validity before clearing calling identity
@@ -2288,7 +2289,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
+ " attribute=" + attribute
+ " controlFlags=#" + Integer.toHexString(controlFlags)
- + " softInputMode=#" + Integer.toHexString(softInputMode)
+ + " softInputMode=" + InputMethodClient.softInputModeToString(softInputMode)
+ " windowFlags=#" + Integer.toHexString(windowFlags));
ClientState cs = mClients.get(client.asBinder());
@@ -2333,6 +2334,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return null;
}
mCurFocusedWindow = windowToken;
+ mCurFocusedWindowSoftInputMode = softInputMode;
mCurFocusedWindowClient = cs;
// Should we auto-show the IME even if the caller has not
@@ -2896,26 +2898,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ---------------------------------------------------------
case MSG_START_INPUT: {
- int missingMethods = msg.arg1;
- args = (SomeArgs) msg.obj;
- try {
- SessionState session = (SessionState) args.arg1;
- setEnabledSessionInMainThread(session);
- session.method.startInput((IInputContext) args.arg2, missingMethods,
- (EditorInfo) args.arg3);
- } catch (RemoteException e) {
- }
- args.recycle();
- return true;
- }
- case MSG_RESTART_INPUT: {
- int missingMethods = msg.arg1;
+ final int missingMethods = msg.arg1;
+ final boolean restarting = msg.arg2 != 0;
args = (SomeArgs) msg.obj;
+ final SessionState session = (SessionState) args.arg1;
+ final IInputContext inputContext = (IInputContext) args.arg2;
+ final EditorInfo editorInfo = (EditorInfo) args.arg3;
try {
- SessionState session = (SessionState) args.arg1;
setEnabledSessionInMainThread(session);
- session.method.restartInput((IInputContext) args.arg2, missingMethods,
- (EditorInfo) args.arg3);
+ session.method.startInput(inputContext, missingMethods, editorInfo, restarting);
} catch (RemoteException e) {
}
args.recycle();
@@ -4087,9 +4078,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" mCurMethodId=" + mCurMethodId);
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
- p.println(" mCurFocusedWindow=" + mCurFocusedWindow);
+ p.println(" mCurFocusedWindow=" + mCurFocusedWindow
+ + " softInputMode=" +
+ InputMethodClient.softInputModeToString(mCurFocusedWindowSoftInputMode)
+ + " client=" + mCurFocusedWindowClient);
focusedWindowClient = mCurFocusedWindowClient;
- p.println(" mCurFocusedWindowClient=" + focusedWindowClient);
p.println(" mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
+ " mBoundToMethod=" + mBoundToMethod);
p.println(" mCurToken=" + mCurToken);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c07add0267cb..32b7e4d1b5b4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -59,6 +59,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
@@ -3291,6 +3292,18 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ @Override
+ public long getAllocatableBytes(String path, int flags) {
+ return new File(path).getUsableSpace();
+ }
+
+ @Override
+ public void allocateBytes(String path, long bytes, int flags) {
+ if (bytes > new File(path).getUsableSpace()) {
+ throw new ParcelableException(new IOException("Not enough usable space"));
+ }
+ }
+
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
diff --git a/services/tests/servicestests/src/com/android/server/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
index 031a3b39055a..17c8ec2fac13 100644
--- a/services/tests/servicestests/src/com/android/server/MockStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/MockStorageManager.java
@@ -490,4 +490,14 @@ public class MockStorageManager implements IStorageManager {
throw new UnsupportedOperationException();
}
+ @Override
+ public long getAllocatableBytes(String path, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void allocateBytes(String path, long bytes, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index f7e0f8f55fd4..0501a3bb5fca 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -1634,7 +1634,7 @@ class LinkCommand {
if (options_.static_lib) {
if (options_.table_splitter_options.config_filter != nullptr ||
- options_.table_splitter_options.preferred_density) {
+ !options_.table_splitter_options.preferred_densities.empty()) {
context_->GetDiagnostics()
->Warn(DiagMessage()
<< "can't strip resources when building static library");
@@ -2107,8 +2107,7 @@ int Link(const std::vector<StringPiece>& args) {
<< "Preferred density must only be a density value");
return 1;
}
- options.table_splitter_options.preferred_density =
- preferred_density_config.density;
+ options.table_splitter_options.preferred_densities.push_back(preferred_density_config.density);
}
if (!options.static_lib && stable_id_file_path) {
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 38cfd2e61054..27e13d81ff49 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -19,6 +19,7 @@
#include <algorithm>
#include <map>
#include <set>
+#include <unordered_set>
#include <unordered_map>
#include <vector>
@@ -124,29 +125,35 @@ class SplitValueSelector {
* leaving only the preferred density behind.
*/
static void MarkNonPreferredDensitiesAsClaimed(
- uint16_t preferred_density, const ConfigDensityGroups& density_groups,
+ const std::vector<uint16_t>& preferred_densities, const ConfigDensityGroups& density_groups,
ConfigClaimedMap* config_claimed_map) {
for (auto& entry : density_groups) {
const ConfigDescription& config = entry.first;
const std::vector<ResourceConfigValue*>& related_values = entry.second;
- ConfigDescription target_density = config;
- target_density.density = preferred_density;
- ResourceConfigValue* best_value = nullptr;
+ // There can be multiple best values if there are multiple preferred densities.
+ std::unordered_set<ResourceConfigValue*> best_values;
+
+ // For each preferred density, find the value that is the best.
+ for (uint16_t preferred_density : preferred_densities) {
+ ConfigDescription target_density = config;
+ target_density.density = preferred_density;
+ ResourceConfigValue* best_value = nullptr;
+ for (ResourceConfigValue* this_value : related_values) {
+ if (!best_value || this_value->config.isBetterThan(best_value->config, &target_density)) {
+ best_value = this_value;
+ }
+ }
+ CHECK(best_value != nullptr);
+ best_values.insert(best_value);
+ }
+
+ // Claim all the values that aren't the best so that they will be removed from the base.
for (ResourceConfigValue* this_value : related_values) {
- if (!best_value) {
- best_value = this_value;
- } else if (this_value->config.isBetterThan(best_value->config,
- &target_density)) {
- // Claim the previous value so that it is not included in the base.
- (*config_claimed_map)[best_value] = true;
- best_value = this_value;
- } else {
- // Claim this value so that it is not included in the base.
+ if (best_values.find(this_value) == best_values.end()) {
(*config_claimed_map)[this_value] = true;
}
}
- CHECK(best_value != nullptr);
}
}
bool TableSplitter::VerifySplitConstraints(IAaptContext* context) {
@@ -263,8 +270,8 @@ void TableSplitter::SplitTable(ResourceTable* original_table) {
}
}
- if (options_.preferred_density) {
- MarkNonPreferredDensitiesAsClaimed(options_.preferred_density.value(),
+ if (!options_.preferred_densities.empty()) {
+ MarkNonPreferredDensitiesAsClaimed(options_.preferred_densities,
density_groups,
&config_claimed_map);
}
diff --git a/tools/aapt2/split/TableSplitter.h b/tools/aapt2/split/TableSplitter.h
index 1ae327120796..6aec2576261e 100644
--- a/tools/aapt2/split/TableSplitter.h
+++ b/tools/aapt2/split/TableSplitter.h
@@ -34,14 +34,14 @@ struct SplitConstraints {
struct TableSplitterOptions {
/**
- * The preferred density to keep in the table, stripping out all others.
+ * The preferred densities to keep in the table, stripping out all others.
+ * If empty, no stripping is done.
*/
- Maybe<uint16_t> preferred_density;
+ std::vector<uint16_t> preferred_densities;
/**
* Configuration filter that determines which resource configuration values
- * end up in
- * the final table.
+ * end up in the final table.
*/
IConfigFilter* config_filter = nullptr;
};
diff --git a/tools/aapt2/split/TableSplitter_test.cpp b/tools/aapt2/split/TableSplitter_test.cpp
index 088dac374458..d52f4b446b8f 100644
--- a/tools/aapt2/split/TableSplitter_test.cpp
+++ b/tools/aapt2/split/TableSplitter_test.cpp
@@ -39,7 +39,7 @@ TEST(TableSplitterTest, NoSplitPreferredDensity) {
.Build();
TableSplitterOptions options;
- options.preferred_density = ConfigDescription::DENSITY_XHIGH;
+ options.preferred_densities.push_back(ConfigDescription::DENSITY_XHIGH);
TableSplitter splitter({}, options);
splitter.SplitTable(table.get());
@@ -58,6 +58,51 @@ TEST(TableSplitterTest, NoSplitPreferredDensity) {
EXPECT_NE(nullptr, test::GetValue<Id>(table.get(), "android:string/one"));
}
+TEST(TableSplitterTest, NoSplitMultiplePreferredDensities) {
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:drawable/icon",
+ "res/drawable-mdpi/icon.png",
+ test::ParseConfigOrDie("mdpi"))
+ .AddFileReference("android:drawable/icon",
+ "res/drawable-hdpi/icon.png",
+ test::ParseConfigOrDie("hdpi"))
+ .AddFileReference("android:drawable/icon",
+ "res/drawable-xhdpi/icon.png",
+ test::ParseConfigOrDie("xhdpi"))
+ .AddFileReference("android:drawable/icon",
+ "res/drawable-xxhdpi/icon.png",
+ test::ParseConfigOrDie("xxhdpi"))
+ .AddSimple("android:string/one")
+ .Build();
+
+ TableSplitterOptions options;
+ options.preferred_densities.push_back(ConfigDescription::DENSITY_LOW);
+ options.preferred_densities.push_back(ConfigDescription::DENSITY_XXXHIGH);
+ TableSplitter splitter({}, options);
+ splitter.SplitTable(table.get());
+
+ // Densities remaining:
+ // "mdpi" is the closest available density for the requested "ldpi" density.
+ EXPECT_NE(nullptr, test::GetValueForConfig<FileReference>(
+ table.get(), "android:drawable/icon",
+ test::ParseConfigOrDie("mdpi")));
+ // "xxhdpi" is the closest available density for the requested "xxxhdpi" density.
+ EXPECT_NE(nullptr, test::GetValueForConfig<FileReference>(
+ table.get(), "android:drawable/icon",
+ test::ParseConfigOrDie("xxhdpi")));
+ EXPECT_NE(nullptr, test::GetValue<Id>(table.get(), "android:string/one"));
+
+ // Removed densities:
+ EXPECT_EQ(nullptr, test::GetValueForConfig<FileReference>(
+ table.get(), "android:drawable/icon",
+ test::ParseConfigOrDie("hdpi")));
+ EXPECT_EQ(nullptr, test::GetValueForConfig<FileReference>(
+ table.get(), "android:drawable/icon",
+ test::ParseConfigOrDie("xhdpi")));
+}
+
+
TEST(TableSplitterTest, SplitTableByDensity) {
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
diff --git a/tools/aapt2/strip/Strip.cpp b/tools/aapt2/strip/Strip.cpp
index c34cfbf3580e..7260649c26d4 100644
--- a/tools/aapt2/strip/Strip.cpp
+++ b/tools/aapt2/strip/Strip.cpp
@@ -79,18 +79,13 @@ class StripCommand {
context_->GetDiagnostics()->Note(DiagMessage() << "Stripping APK...");
}
- // TODO(lecesne): Add support for more than one density.
- if (options_.target_configs.size() > 1) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "Multiple densities not supported at the moment");
- return 1;
- }
-
// Stripping the APK using the TableSplitter with no splits and the target
- // density as the preferred density. The resource table is modified in
+ // densities as the preferred densities. The resource table is modified in
// place in the LoadedApk.
TableSplitterOptions splitter_options;
- splitter_options.preferred_density = options_.target_configs[0].density;
+ for (auto& config : options_.target_configs) {
+ splitter_options.preferred_densities.push_back(config.density);
+ }
std::vector<SplitConstraints> splits;
TableSplitter splitter(splits, splitter_options);
splitter.SplitTable(apk->GetResourceTable());
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 468710bbb470..4338ca0eacdc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -228,7 +228,8 @@ public class BridgeIInputMethodManager implements IInputMethodManager {
@Override
public InputBindResult startInputOrWindowGainedFocus(
/* @InputMethodClient.StartInputReason */ int startInputReason,
- IInputMethodClient client, IBinder windowToken, int controlFlags, int softInputMode,
+ IInputMethodClient client, IBinder windowToken, int controlFlags,
+ /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags)
throws RemoteException {