Merge "Audio: Flag volume adjustments from hardware keys."
diff --git a/api/current.txt b/api/current.txt
index 7bac613..4e51621 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15145,7 +15145,7 @@
method public void setPropertyString(java.lang.String, java.lang.String);
field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
- field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+ field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
@@ -32918,6 +32918,7 @@
method public boolean getTitleOptionalHint();
method public int getType();
method public abstract void invalidate();
+ method public void invalidateContentRect();
method public boolean isTitleOptional();
method public abstract void setCustomView(android.view.View);
method public abstract void setSubtitle(java.lang.CharSequence);
@@ -32938,6 +32939,11 @@
method public abstract boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
}
+ public static abstract class ActionMode.Callback2 implements android.view.ActionMode.Callback {
+ ctor public ActionMode.Callback2();
+ method public void onGetContentRect(android.view.ActionMode, android.view.View, android.graphics.Rect);
+ }
+
public abstract class ActionProvider {
ctor public ActionProvider(android.content.Context);
method public boolean hasSubMenu();
@@ -37444,6 +37450,7 @@
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
+ method public void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
method public void invokeZoomPicker();
method public boolean isPrivateBrowsingEnabled();
method public void loadData(java.lang.String, java.lang.String, java.lang.String);
@@ -37518,6 +37525,11 @@
method public abstract deprecated void onNewPicture(android.webkit.WebView, android.graphics.Picture);
}
+ public static abstract class WebView.VisualStateCallback {
+ ctor public WebView.VisualStateCallback();
+ method public abstract void onComplete(long);
+ }
+
public class WebView.WebViewTransport {
ctor public WebView.WebViewTransport();
method public synchronized android.webkit.WebView getWebView();
@@ -37529,6 +37541,7 @@
method public void doUpdateVisitedHistory(android.webkit.WebView, java.lang.String, boolean);
method public void onFormResubmission(android.webkit.WebView, android.os.Message, android.os.Message);
method public void onLoadResource(android.webkit.WebView, java.lang.String);
+ method public void onPageCommitVisible(android.webkit.WebView, java.lang.String);
method public void onPageFinished(android.webkit.WebView, java.lang.String);
method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
diff --git a/api/system-current.txt b/api/system-current.txt
index 89c0460e..d0dd852 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -16334,7 +16334,7 @@
method public void unprovisionDevice();
field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
- field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+ field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
@@ -35274,6 +35274,7 @@
method public boolean getTitleOptionalHint();
method public int getType();
method public abstract void invalidate();
+ method public void invalidateContentRect();
method public boolean isTitleOptional();
method public abstract void setCustomView(android.view.View);
method public abstract void setSubtitle(java.lang.CharSequence);
@@ -35294,6 +35295,11 @@
method public abstract boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
}
+ public static abstract class ActionMode.Callback2 implements android.view.ActionMode.Callback {
+ ctor public ActionMode.Callback2();
+ method public void onGetContentRect(android.view.ActionMode, android.view.View, android.graphics.Rect);
+ }
+
public abstract class ActionProvider {
ctor public ActionProvider(android.content.Context);
method public boolean hasSubMenu();
@@ -39876,6 +39882,7 @@
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
+ method public void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
method public void invokeZoomPicker();
method public boolean isPrivateBrowsingEnabled();
method public void loadData(java.lang.String, java.lang.String, java.lang.String);
@@ -39980,6 +39987,11 @@
method public void super_setLayoutParams(android.view.ViewGroup.LayoutParams);
}
+ public static abstract class WebView.VisualStateCallback {
+ ctor public WebView.VisualStateCallback();
+ method public abstract void onComplete(long);
+ }
+
public class WebView.WebViewTransport {
ctor public WebView.WebViewTransport();
method public synchronized android.webkit.WebView getWebView();
@@ -39991,6 +40003,7 @@
method public void doUpdateVisitedHistory(android.webkit.WebView, java.lang.String, boolean);
method public void onFormResubmission(android.webkit.WebView, android.os.Message, android.os.Message);
method public void onLoadResource(android.webkit.WebView, java.lang.String);
+ method public void onPageCommitVisible(android.webkit.WebView, java.lang.String);
method public void onPageFinished(android.webkit.WebView, java.lang.String);
method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
@@ -40137,6 +40150,7 @@
method public abstract void goBackOrForward(int);
method public abstract void goForward();
method public abstract void init(java.util.Map<java.lang.String, java.lang.Object>, boolean);
+ method public abstract void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
method public abstract void invokeZoomPicker();
method public abstract boolean isPaused();
method public abstract boolean isPrivateBrowsingEnabled();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2ed8c44..f685475 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2790,6 +2790,31 @@
/** {@hide} */
public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
+ /**
+ * Broadcast action: report that a settings element is being restored from backup. The intent
+ * contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting,
+ * EXTRA_SETTING_NEW_VALUE is the value being restored, and EXTRA_SETTING_PREVIOUS_VALUE
+ * is the value of that settings entry prior to the restore operation. All of these values are
+ * represented as strings.
+ *
+ * <p>This broadcast is sent only for settings provider entries known to require special handling
+ * around restore time. These entries are found in the BROADCAST_ON_RESTORE table within
+ * the provider's backup agent implementation.
+ *
+ * @see #EXTRA_SETTING_NAME
+ * @see #EXTRA_SETTING_PREVIOUS_VALUE
+ * @see #EXTRA_SETTING_NEW_VALUE
+ * {@hide}
+ */
+ public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
+
+ /** {@hide} */
+ public static final String EXTRA_SETTING_NAME = "setting_name";
+ /** {@hide} */
+ public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
+ /** {@hide} */
+ public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 367a078..b5a019d 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -292,6 +292,10 @@
Log.e(TAG, "configureOutputs - null outputs are not allowed");
return BAD_VALUE;
}
+ if (!output.isValid()) {
+ Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
+ return BAD_VALUE;
+ }
StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
@@ -522,7 +526,7 @@
* @return the width and height of the surface
*
* @throws NullPointerException if the {@code surface} was {@code null}
- * @throws IllegalStateException if the {@code surface} was invalid
+ * @throws BufferQueueAbandonedException if the {@code surface} was invalid
*/
public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
checkNotNull(surface);
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 7e0c01b..4b7cfbf 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -60,7 +60,7 @@
case CameraBinderDecorator.NO_ERROR: {
return CameraBinderDecorator.NO_ERROR;
}
- case CameraBinderDecorator.ENODEV: {
+ case CameraBinderDecorator.BAD_VALUE: {
throw new BufferQueueAbandonedException();
}
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index ff74c59..691798f 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -498,6 +498,10 @@
return;
}
for(Surface s : surfaces) {
+ if (s == null || !s.isValid()) {
+ Log.w(TAG, "Jpeg surface is invalid, skipping...");
+ continue;
+ }
try {
LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB);
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e303f61..de970cb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -364,6 +364,12 @@
public static final int GO_TO_SLEEP_REASON_HDMI = 5;
/**
+ * Go to sleep reason code: Going to sleep due to the sleep button being pressed.
+ * @hide
+ */
+ public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6;
+
+ /**
* Go to sleep flag: Skip dozing state and directly go to full sleep.
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4c452aa..3813277 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5374,6 +5374,7 @@
ACCESSIBILITY_SCRIPT_INJECTION,
BACKUP_AUTO_RESTORE,
ENABLED_ACCESSIBILITY_SERVICES,
+ ENABLED_NOTIFICATION_LISTENERS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
@@ -5398,6 +5399,9 @@
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global
WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global
WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global
+ SELECTED_SPELL_CHECKER,
+ SELECTED_SPELL_CHECKER_SUBTYPE,
+ SPELL_CHECKER_ENABLED,
MOUNT_PLAY_NOTIFICATION_SND,
MOUNT_UMS_AUTOSTART,
MOUNT_UMS_PROMPT,
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index a018138..9f202a9 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,6 +18,7 @@
import android.annotation.StringRes;
+import android.graphics.Rect;
/**
* Represents a contextual mode of the user interface. Action modes can be used to provide
@@ -197,6 +198,15 @@
public abstract void invalidate();
/**
+ * Invalidate the content rect associated to this ActionMode. This only makes sense for
+ * action modes that support dynamic positioning on the screen, and provides a more efficient
+ * way to reposition it without invalidating the whole action mode.
+ *
+ * @see Callback2#onGetContentRect(ActionMode, View, Rect) .
+ */
+ public void invalidateContentRect() {}
+
+ /**
* Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
* have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
*/
@@ -298,4 +308,31 @@
*/
public void onDestroyActionMode(ActionMode mode);
}
-}
\ No newline at end of file
+
+ /**
+ * Extension of {@link ActionMode.Callback} to provide content rect information. This is
+ * required for ActionModes with dynamic positioning such as the ones with type
+ * {@link ActionMode#TYPE_FLOATING} to ensure the positioning doesn't obscure app content. If
+ * an app fails to provide a subclass of this class, a default implementation will be used.
+ */
+ public static abstract class Callback2 implements ActionMode.Callback {
+
+ /**
+ * Called when an ActionMode needs to be positioned on screen, potentially occluding view
+ * content. Note this may be called on a per-frame basis.
+ *
+ * @param mode The ActionMode that requires positioning.
+ * @param view The View that originated the ActionMode, in whose coordinates the Rect should
+ * be provided.
+ * @param outRect The Rect to be populated with the content position.
+ */
+ public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+ if (view != null) {
+ outRect.set(0, 0, view.getWidth(), view.getHeight());
+ } else {
+ outRect.set(0, 0, 0, 0);
+ }
+ }
+
+ }
+}
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index c6c1481..543021e 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -2670,17 +2670,13 @@
@Override
public ActionMode startActionModeForChild(View originalView,
ActionMode.Callback callback) {
- // originalView can be used here to be sure that we don't obscure
- // relevant content with the context mode UI.
- return startActionMode(callback);
+ return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
}
@Override
public ActionMode startActionModeForChild(
View child, ActionMode.Callback callback, int type) {
- // originalView can be used here to be sure that we don't obscure
- // relevant content with the context mode UI.
- return startActionMode(callback, type);
+ return startActionMode(child, callback, type);
}
@Override
@@ -2690,7 +2686,12 @@
@Override
public ActionMode startActionMode(ActionMode.Callback callback, int type) {
- ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
+ return startActionMode(this, callback, type);
+ }
+
+ private ActionMode startActionMode(
+ View originatingView, ActionMode.Callback callback, int type) {
+ ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
ActionMode mode = null;
if (getCallback() != null && !isDestroyed()) {
try {
@@ -3292,12 +3293,12 @@
}
/**
- * Clears out internal reference when the action mode is destroyed.
+ * Clears out internal references when the action mode is destroyed.
*/
- private class ActionModeCallbackWrapper implements ActionMode.Callback {
- private ActionMode.Callback mWrapped;
+ private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
+ private final ActionMode.Callback mWrapped;
- public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
+ public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
mWrapped = wrapped;
}
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index e1942be..a75e8a7 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -573,7 +573,7 @@
if (other.mType != mType) {
throw new IllegalArgumentException("Not same type.");
}
- if (!mBoundsInScreen.equals(mBoundsInScreen)) {
+ if (!mBoundsInScreen.equals(other.mBoundsInScreen)) {
return true;
}
if (mLayer != other.mLayer) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 67ad642..6711a6b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -364,6 +364,20 @@
}
/**
+ * Callback interface supplied to {@link #insertVisualStateCallback} for receiving
+ * notifications about the visual state.
+ */
+ public static abstract class VisualStateCallback {
+ /**
+ * Invoked when the visual state is ready to be drawn in the next {@link #onDraw}.
+ *
+ * @param requestId the id supplied to the corresponding {@link #insertVisualStateCallback}
+ * request
+ */
+ public abstract void onComplete(long requestId);
+ }
+
+ /**
* Interface to listen for new pictures as they change.
*
* @deprecated This interface is now obsolete.
@@ -1144,6 +1158,60 @@
}
/**
+ * Inserts a {@link VisualStateCallback}.
+ *
+ * <p>Updates to the the DOM are reflected asynchronously such that when the DOM is updated the
+ * subsequent {@link WebView#onDraw} invocation might not reflect those updates. The
+ * {@link VisualStateCallback} provides a mechanism to notify the caller when the contents of
+ * the DOM at the current time are ready to be drawn the next time the {@link WebView} draws.
+ * By current time we mean the time at which this API was called. The next draw after the
+ * callback completes is guaranteed to reflect all the updates to the DOM applied before the
+ * current time, but it may also contain updates applied after the current time.</p>
+ *
+ * <p>The state of the DOM covered by this API includes the following:
+ * <ul>
+ * <li>primitive HTML elements (div, img, span, etc..)</li>
+ * <li>images</li>
+ * <li>CSS animations</li>
+ * <li>WebGL</li>
+ * <li>canvas</li>
+ * </ul>
+ * It does not include the state of:
+ * <ul>
+ * <li>the video tag</li>
+ * </ul></p>
+ *
+ * <p>To guarantee that the {@link WebView} will successfully render the first frame
+ * after the {@link VisualStateCallback#onComplete} method has been called a set of conditions
+ * must be met:
+ * <ul>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#VISIBLE VISIBLE} then
+ * the {@link WebView} must be attached to the view hierarchy.</li>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#INVISIBLE INVISIBLE}
+ * then the {@link WebView} must be attached to the view hierarchy and must be made
+ * {@link View#VISIBLE VISIBLE} from the {@link VisualStateCallback#onComplete} method.</li>
+ * <li>If the {@link WebView}'s visibility is set to {@link View#GONE GONE} then the
+ * {@link WebView} must be attached to the view hierarchy and its
+ * {@link AbsoluteLayout.LayoutParams LayoutParams}'s width and height need to be set to fixed
+ * values and must be made {@link View#VISIBLE VISIBLE} from the
+ * {@link VisualStateCallback#onComplete} method.</li>
+ * </ul></p>
+ *
+ * <p>When using this API it is also recommended to enable pre-rasterization if the
+ * {@link WebView} is offscreen to avoid flickering. See WebSettings#setOffscreenPreRaster for
+ * more details and do consider its caveats.</p>
+ *
+ * @param requestId an id that will be returned in the callback to allow callers to match
+ * requests with callbacks.
+ * @param callback the callback to be invoked.
+ */
+ public void insertVisualStateCallback(long requestId, VisualStateCallback callback) {
+ checkThread();
+ if (TRACE) Log.d(LOGTAG, "insertVisualStateCallback");
+ mProvider.insertVisualStateCallback(requestId, callback);
+ }
+
+ /**
* Clears this WebView so that onDraw() will draw nothing but white background,
* and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY.
* @deprecated Use WebView.loadUrl("about:blank") to reliably reset the view state
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 34b8cf6..53c7e04 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -83,6 +83,32 @@
}
/**
+ * Notify the host application that the page commit is visible.
+ *
+ * <p>This is the earliest point at which we can guarantee that the contents of the previously
+ * loaded page will not longer be drawn in the next {@link WebView#onDraw}. The next draw will
+ * render the {@link WebView#setBackgroundColor background color} of the WebView or some of the
+ * contents from the committed page already. This callback may be useful when reusing
+ * {@link WebView}s to ensure that no stale content is shown. This method is only called for
+ * the main frame.</p>
+ *
+ * <p>This method is called when the state of the DOM at the point at which the
+ * body of the HTTP response (commonly the string of html) had started loading will be visible.
+ * If you set a background color for the page in the HTTP response body this will most likely
+ * be visible and perhaps some other elements. At that point no other resources had usually
+ * been loaded, so you can expect images for example to not be visible. If you want
+ * a finer level of granularity consider calling {@link WebView#insertVisualStateCallback}
+ * directly.</p>
+ *
+ * <p>Please note that all the conditions and recommendations presented in
+ * {@link WebView#insertVisualStateCallback} also apply to this API.<p>
+ *
+ * @param url the url of the committed page
+ */
+ public void onPageCommitVisible(WebView view, String url) {
+ }
+
+ /**
* Notify the host application of a resource request and allow the
* application to return the data. If the return value is null, the WebView
* will continue to load the resource as usual. Otherwise, the return
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 0cdb875..fa2ce1b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -40,6 +40,8 @@
import android.view.inputmethod.InputConnection;
import android.webkit.WebView.HitTestResult;
import android.webkit.WebView.PictureListener;
+import android.webkit.WebView.VisualStateCallback;
+
import java.io.BufferedWriter;
import java.io.File;
@@ -146,6 +148,8 @@
public boolean pageDown(boolean bottom);
+ public void insertVisualStateCallback(long requestId, VisualStateCallback callback);
+
public void clearView();
public Picture capturePicture();
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 2bf02f1..7ae7d0f 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -23,7 +23,6 @@
import com.android.internal.R;
import com.android.internal.view.ActionBarPolicy;
-import com.android.internal.view.ActionModeWrapper;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 29326d3a..57fcf57 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -120,18 +120,6 @@
& ApplicationInfo.FLAG_SYSTEM) != 0;
}
- /**
- * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
- * Locale, boolean, String)} instead.
- */
- @Deprecated
- public static boolean isSystemImeThatHasEnglishKeyboardSubtype(InputMethodInfo imi) {
- if (!isSystemIme(imi)) {
- return false;
- }
- return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
- }
-
public static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
final Context context, final boolean checkDefaultAttribute,
@Nullable final Locale requiredLocale, final boolean checkCountry,
@@ -382,35 +370,6 @@
.build();
}
- /**
- * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
- * Locale, boolean, String)} instead.
- */
- @Deprecated
- public static boolean isValidSystemDefaultIme(
- boolean isSystemReady, InputMethodInfo imi, Context context) {
- if (!isSystemReady) {
- return false;
- }
- if (!isSystemIme(imi)) {
- return false;
- }
- if (imi.getIsDefaultResourceId() != 0) {
- try {
- if (imi.isDefault(context) && containsSubtypeOf(
- imi, context.getResources().getConfiguration().locale.getLanguage(),
- SUBTYPE_MODE_ANY)) {
- return true;
- }
- } catch (Resources.NotFoundException ex) {
- }
- }
- if (imi.getSubtypeCount() == 0) {
- Slog.w(TAG, "Found no subtypes in a system IME: " + imi.getPackageName());
- }
- return false;
- }
-
public static Locale constructLocaleFromString(String localeStr) {
if (TextUtils.isEmpty(localeStr)) {
return null;
@@ -459,25 +418,6 @@
return false;
}
- /**
- * @deprecated Use {@link #containsSubtypeOf(InputMethodInfo, Locale, boolean, String)} instead.
- */
- @Deprecated
- public static boolean containsSubtypeOf(InputMethodInfo imi, String language, String mode) {
- final int N = imi.getSubtypeCount();
- for (int i = 0; i < N; ++i) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- if (!subtype.getLocale().startsWith(language)) {
- continue;
- }
- if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
- mode.equalsIgnoreCase(subtype.getMode())) {
- return true;
- }
- }
- return false;
- }
-
public static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
final int subtypeCount = imi.getSubtypeCount();
@@ -510,12 +450,15 @@
while (i > 0) {
i--;
final InputMethodInfo imi = enabledImes.get(i);
- if (InputMethodUtils.isSystemImeThatHasEnglishKeyboardSubtype(imi)
- && !imi.isAuxiliaryIme()) {
+ if (imi.isAuxiliaryIme()) {
+ continue;
+ }
+ if (InputMethodUtils.isSystemIme(imi)
+ && containsSubtypeOf(imi, ENGLISH_LOCALE, false /* checkCountry */,
+ SUBTYPE_MODE_KEYBOARD)) {
return imi;
}
- if (firstFoundSystemIme < 0 && InputMethodUtils.isSystemIme(imi)
- && !imi.isAuxiliaryIme()) {
+ if (firstFoundSystemIme < 0 && InputMethodUtils.isSystemIme(imi)) {
firstFoundSystemIme = i;
}
}
diff --git a/core/java/com/android/internal/view/ActionModeWrapper.java b/core/java/com/android/internal/view/ActionModeWrapper.java
deleted file mode 100644
index d98617d..0000000
--- a/core/java/com/android/internal/view/ActionModeWrapper.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 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 may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.view;
-
-import android.content.Context;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-import com.android.internal.view.menu.MenuBuilder;
-
-/**
- * ActionMode implementation that wraps several actions modes and creates them on the fly depending
- * on the ActionMode type chosen by the client.
- */
-public class ActionModeWrapper extends ActionMode {
-
- /**
- * Interface to defer the ActionMode creation until the type is chosen.
- */
- public interface ActionModeProvider {
- /**
- * Create the desired ActionMode, that will immediately be used as the current active mode
- * in the decorator.
- *
- * @param callback The {@link ActionMode.Callback} to be used.
- * @param menuBuilder The {@link MenuBuilder} that should be used by the created
- * {@link ActionMode}. This will already have been populated.
- * @return A new {@link ActionMode} ready to be used that uses menuBuilder as its menu.
- */
- ActionMode createActionMode(ActionMode.Callback callback, MenuBuilder menuBuilder);
- }
-
- private ActionMode mActionMode;
- private final Context mContext;
- private MenuBuilder mMenu;
- private final ActionMode.Callback mCallback;
- private boolean mTypeLocked = false;
-
- private CharSequence mTitle;
- private CharSequence mSubtitle;
- private View mCustomView;
-
- private final ActionModeProvider mActionModeProvider;
-
- public ActionModeWrapper(
- Context context, ActionMode.Callback callback, ActionModeProvider actionModeProvider) {
- mContext = context;
- mMenu = new MenuBuilder(context).setDefaultShowAsAction(
- MenuItem.SHOW_AS_ACTION_IF_ROOM);
- mCallback = callback;
- mActionModeProvider = actionModeProvider;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- if (mActionMode != null) {
- mActionMode.setTitle(title);
- } else {
- mTitle = title;
- }
- }
-
- @Override
- public void setTitle(int resId) {
- if (mActionMode != null) {
- mActionMode.setTitle(resId);
- } else {
- mTitle = resId != 0 ? mContext.getString(resId) : null;
- }
- }
-
- @Override
- public void setSubtitle(CharSequence subtitle) {
- if (mActionMode != null) {
- mActionMode.setSubtitle(subtitle);
- } else {
- mSubtitle = subtitle;
- }
- }
-
- @Override
- public void setSubtitle(int resId) {
- if (mActionMode != null) {
- mActionMode.setSubtitle(resId);
- } else {
- mSubtitle = resId != 0 ? mContext.getString(resId) : null;
- }
- }
-
- @Override
- public void setCustomView(View view) {
- if (mActionMode != null) {
- mActionMode.setCustomView(view);
- } else {
- mCustomView = view;
- }
- }
-
- public ActionMode getWrappedActionMode() {
- return mActionMode;
- }
-
- /**
- * Set the current type as final and create the necessary ActionMode. After this call, any
- * changes to the ActionMode type will be ignored.
- */
- public void lockType() {
- mTypeLocked = true;
- switch (getType()) {
- case ActionMode.TYPE_PRIMARY:
- default:
- mActionMode = mActionModeProvider.createActionMode(mCallback, mMenu);
- break;
- case ActionMode.TYPE_FLOATING:
- // Not implemented yet.
- break;
- }
-
- if (mActionMode == null) {
- return;
- }
-
- mActionMode.setTitle(mTitle);
- mActionMode.setSubtitle(mSubtitle);
- if (mCustomView != null) {
- mActionMode.setCustomView(mCustomView);
- }
-
- mTitle = null;
- mSubtitle = null;
- mCustomView = null;
- }
-
- @Override
- public void setType(int type) {
- if (!mTypeLocked) {
- super.setType(type);
- } else {
- throw new IllegalStateException(
- "You can't change the ActionMode's type after onCreateActionMode.");
- }
- }
-
- @Override
- public void invalidate() {
- if (mActionMode != null) {
- mActionMode.invalidate();
- }
- }
-
- @Override
- public void finish() {
- if (mActionMode != null) {
- mActionMode.finish();
- } else {
- mCallback.onDestroyActionMode(this);
- }
- }
-
- @Override
- public Menu getMenu() {
- return mMenu;
- }
-
- @Override
- public CharSequence getTitle() {
- if (mActionMode != null) {
- return mActionMode.getTitle();
- }
- return mTitle;
- }
-
- @Override
- public CharSequence getSubtitle() {
- if (mActionMode != null) {
- return mActionMode.getSubtitle();
- }
- return mSubtitle;
- }
-
- @Override
- public View getCustomView() {
- if (mActionMode != null) {
- return mActionMode.getCustomView();
- }
- return mCustomView;
- }
-
- @Override
- public MenuInflater getMenuInflater() {
- return new MenuInflater(mContext);
- }
-
-}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 441af15..2327899 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -649,9 +649,9 @@
/*
* JIT related options.
*/
- parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
- parseRuntimeOption("dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
- parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
+ parseRuntimeOption("debug.dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
+ parseRuntimeOption("debug.dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
+ parseRuntimeOption("debug.dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 87896df..afdfd8f 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -373,8 +373,7 @@
return NULL;
}
if (anw == NULL) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "Surface had no valid native window.");
+ ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
return NULL;
}
return anw;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ed4776b..4d6b5f6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -90,6 +90,8 @@
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" />
+ <protected-broadcast android:name="android.os.action.SETTING_RESTORED" />
+
<protected-broadcast android:name="android.backup.intent.RUN" />
<protected-broadcast android:name="android.backup.intent.CLEAR" />
<protected-broadcast android:name="android.backup.intent.INIT" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a781786..37c9598 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -664,6 +664,12 @@
-->
<integer name="config_triplePressOnPowerBehavior">0</integer>
+ <!-- Control the behavior when the user presses the sleep button.
+ 0 - Go to sleep (doze)
+ 1 - Go to sleep (doze) and go home
+ -->
+ <integer name="config_shortPressOnSleepBehavior">0</integer>
+
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
<string name="widget_default_package_name" translatable="false"></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 20ec563..0617503 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -367,6 +367,7 @@
<java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
<java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
+ <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 824a7ad..18ffe12 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -443,6 +443,7 @@
@Override
public void close() {
setOnImageAvailableListener(null, null);
+ if (mSurface != null) mSurface.release();
nativeClose();
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index d7752b9..6b37a34 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -254,6 +254,9 @@
* This event type indicates that the app needs to request a certificate from
* the provisioning server. The request message data is obtained using
* {@link #getProvisionRequest}
+ *
+ * @deprecated Handle provisioning via {@link android.media.NotProvisionedException}
+ * instead.
*/
public static final int EVENT_PROVISION_REQUIRED = 1;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index eac83d8..7f826ef 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -793,7 +793,7 @@
}
// Figure out the white list and redirects to the global table.
- String[] whitelist = null;
+ final String[] whitelist;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
} else if (contentUri.equals(Settings.System.CONTENT_URI)) {
@@ -809,6 +809,7 @@
Map<String, String> cachedEntries = new HashMap<String, String>();
ContentValues contentValues = new ContentValues(2);
SettingsHelper settingsHelper = mSettingsHelper;
+ ContentResolver cr = getContentResolver();
final int whiteListSize = whitelist.length;
for (int i = 0; i < whiteListSize; i++) {
@@ -841,14 +842,7 @@
final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
? Settings.Global.CONTENT_URI
: contentUri;
-
- // The helper doesn't care what namespace the keys are in
- if (settingsHelper.restoreValue(key, value)) {
- contentValues.clear();
- contentValues.put(Settings.NameValueTable.NAME, key);
- contentValues.put(Settings.NameValueTable.VALUE, value);
- getContentResolver().insert(destination, contentValues);
- }
+ settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
if (DEBUG) {
Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 4144c80..30786f0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -19,7 +19,10 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.backup.IBackupManager;
+import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.location.LocationManager;
import android.media.AudioManager;
@@ -28,10 +31,12 @@
import android.os.IPowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArraySet;
import java.util.Locale;
@@ -41,6 +46,49 @@
private AudioManager mAudioManager;
private TelephonyManager mTelephonyManager;
+ /**
+ * A few settings elements are special in that a restore of those values needs to
+ * be post-processed by relevant parts of the OS. A restore of any settings element
+ * mentioned in this table will therefore cause the system to send a broadcast with
+ * the {@link Intent#ACTION_SETTING_RESTORED} action, with extras naming the
+ * affected setting and supplying its pre-restore value for comparison.
+ *
+ * @see Intent#ACTION_SETTING_RESTORED
+ * @see System#SETTINGS_TO_BACKUP
+ * @see Secure#SETTINGS_TO_BACKUP
+ * @see Global#SETTINGS_TO_BACKUP
+ *
+ * {@hide}
+ */
+ private static final ArraySet<String> sBroadcastOnRestore;
+ static {
+ sBroadcastOnRestore = new ArraySet<String>(2);
+ sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ }
+
+ private interface SettingsLookup {
+ public String lookup(ContentResolver resolver, String name, int userHandle);
+ }
+
+ private static SettingsLookup sSystemLookup = new SettingsLookup() {
+ public String lookup(ContentResolver resolver, String name, int userHandle) {
+ return Settings.System.getStringForUser(resolver, name, userHandle);
+ }
+ };
+
+ private static SettingsLookup sSecureLookup = new SettingsLookup() {
+ public String lookup(ContentResolver resolver, String name, int userHandle) {
+ return Settings.Secure.getStringForUser(resolver, name, userHandle);
+ }
+ };
+
+ private static SettingsLookup sGlobalLookup = new SettingsLookup() {
+ public String lookup(ContentResolver resolver, String name, int userHandle) {
+ return Settings.Global.getStringForUser(resolver, name, userHandle);
+ }
+ };
+
public SettingsHelper(Context context) {
mContext = context;
mAudioManager = (AudioManager) context
@@ -58,24 +106,67 @@
* some cases the data will be written by the call to the appropriate API,
* and in some cases the property value needs to be modified before setting.
*/
- public boolean restoreValue(String name, String value) {
- if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) {
- setBrightness(Integer.parseInt(value));
- } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
- setSoundEffects(Integer.parseInt(value) == 1);
- } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
- setGpsLocation(value);
- return false;
- } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) {
- setAutoRestore(Integer.parseInt(value) == 1);
- } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
- return false;
- } else if (Settings.System.RINGTONE.equals(name)
- || Settings.System.NOTIFICATION_SOUND.equals(name)) {
- setRingtone(name, value);
- return false;
+ public void restoreValue(Context context, ContentResolver cr, ContentValues contentValues,
+ Uri destination, String name, String value) {
+ // Will we need a post-restore broadcast for this element?
+ String oldValue = null;
+ boolean sendBroadcast = false;
+ final SettingsLookup table;
+
+ if (destination.equals(Settings.Secure.CONTENT_URI)) {
+ table = sSecureLookup;
+ } else if (destination.equals(Settings.System.CONTENT_URI)) {
+ table = sSystemLookup;
+ } else { /* must be GLOBAL; this was preflighted by the caller */
+ table = sGlobalLookup;
}
- return true;
+
+ if (sBroadcastOnRestore.contains(name)) {
+ oldValue = table.lookup(cr, name, UserHandle.USER_OWNER);
+ sendBroadcast = true;
+ }
+
+ try {
+ if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) {
+ setBrightness(Integer.parseInt(value));
+ // fall through to the ordinary write to settings
+ } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
+ setSoundEffects(Integer.parseInt(value) == 1);
+ // fall through to the ordinary write to settings
+ } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+ setGpsLocation(value);
+ return;
+ } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) {
+ setAutoRestore(Integer.parseInt(value) == 1);
+ } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
+ return;
+ } else if (Settings.System.RINGTONE.equals(name)
+ || Settings.System.NOTIFICATION_SOUND.equals(name)) {
+ setRingtone(name, value);
+ return;
+ }
+
+ // Default case: write the restored value to settings
+ contentValues.clear();
+ contentValues.put(Settings.NameValueTable.NAME, name);
+ contentValues.put(Settings.NameValueTable.VALUE, value);
+ cr.insert(destination, contentValues);
+ } catch (Exception e) {
+ // If we fail to apply the setting, by definition nothing happened
+ sendBroadcast = false;
+ } finally {
+ // If this was an element of interest, send the "we just restored it"
+ // broadcast with the historical value now that the new value has
+ // been committed and observers kicked off.
+ if (sendBroadcast) {
+ Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
+ .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .putExtra(Intent.EXTRA_SETTING_NAME, name)
+ .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
+ .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue);
+ context.sendBroadcastAsUser(intent, UserHandle.OWNER, null);
+ }
+ }
}
public String onBackupValue(String name, String value) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a712d78..bb5ff1b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -352,6 +352,7 @@
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
+ intentFilter.addAction(Intent.ACTION_SETTING_RESTORED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -369,6 +370,15 @@
onUserStateChangedLocked(userState);
}
}
+ } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
+ final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+ if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) {
+ synchronized (mLock) {
+ restoreEnabledAccessibilityServicesLocked(
+ intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ }
+ }
}
}
}, UserHandle.ALL, intentFilter, null, null);
@@ -857,6 +867,21 @@
}
}
+ // Called only during settings restore; currently supports only the owner user
+ void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
+ readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
+ readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
+
+ UserState userState = getUserStateLocked(UserHandle.USER_OWNER);
+ userState.mEnabledServices.clear();
+ userState.mEnabledServices.addAll(mTempComponentNameSet);
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userState.mEnabledServices,
+ UserHandle.USER_OWNER);
+ onUserStateChangedLocked(userState);
+ }
+
private InteractionBridge getInteractionBridgeLocked() {
if (mInteractionBridge == null) {
mInteractionBridge = new InteractionBridge();
@@ -1129,10 +1154,27 @@
Set<ComponentName> outComponentNames) {
String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
settingName, userId);
- outComponentNames.clear();
- if (settingValue != null) {
+ readComponentNamesFromStringLocked(settingValue, outComponentNames, false);
+ }
+
+ /**
+ * Populates a set with the {@link ComponentName}s contained in a colon-delimited string.
+ *
+ * @param names The colon-delimited string to parse.
+ * @param outComponentNames The set of component names to be populated based on
+ * the contents of the <code>names</code> string.
+ * @param doMerge If true, the parsed component names will be merged into the output
+ * set, rather than replacing the set's existing contents entirely.
+ */
+ private void readComponentNamesFromStringLocked(String names,
+ Set<ComponentName> outComponentNames,
+ boolean doMerge) {
+ if (!doMerge) {
+ outComponentNames.clear();
+ }
+ if (names != null) {
TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
- splitter.setString(settingValue);
+ splitter.setString(names);
while (splitter.hasNext()) {
String str = splitter.next();
if (str == null || str.length() <= 0) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4d0868a..9ec886c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -764,9 +764,11 @@
InputMethodInfo defIm = null;
for (InputMethodInfo imi : mMethodList) {
- if (defIm == null) {
- if (InputMethodUtils.isValidSystemDefaultIme(
- mSystemReady, imi, context)) {
+ if (defIm == null && mSystemReady) {
+ final Locale systemLocale = context.getResources().getConfiguration().locale;
+ if (InputMethodUtils.isSystemImeThatHasSubtypeOf(imi, context,
+ true /* checkDefaultAttribute */, systemLocale, false /* checkCountry */,
+ InputMethodUtils.SUBTYPE_MODE_ANY)) {
defIm = imi;
Slog.i(TAG, "Selected default: " + imi.getId());
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index ae4006d..fd4974e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -30,10 +30,10 @@
// will be tagged with their class names instead fot the generic tag.
static final boolean TAG_WITH_CLASS_NAME = false;
- // While debugging it is sometimes useful to have the category name of the log prepended to the
+ // While debugging it is sometimes useful to have the category name of the log appended to the
// base log tag to make sifting through logs with the same base tag easier. By setting this
- // constant to true, the category name of the log point will be prepended to the log tag.
- static final boolean PREPEND_CATEGORY_NAME = false;
+ // constant to true, the category name of the log point will be appended to the log tag.
+ static final boolean APPEND_CATEGORY_NAME = false;
// Default log tag for the activity manager package.
static final String TAG_AM = "ActivityManager";
@@ -74,12 +74,17 @@
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
- static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
- static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
- static final String POSTFIX_CLEANUP = (PREPEND_CATEGORY_NAME) ? "_Cleanup" : "";
+ static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
+ static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+ static final String POSTFIX_CLEANUP = (APPEND_CATEGORY_NAME) ? "_Cleanup" : "";
+ static final String POSTFIX_CONFIGURATION = (APPEND_CATEGORY_NAME) ? "_Configuration" : "";
+ static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
+ static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
+ static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
static final String POSTFIX_MU = "_MU";
- static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
+ static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
+ static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
static final String POSTFIX_SERVICE_EXECUTING =
- (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+ (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a366c7b..dcee96a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -254,15 +254,14 @@
private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+ private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
+ private static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
+ private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
// TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
- static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
- static final boolean DEBUG_FOCUS = false;
- static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
- static final boolean DEBUG_MU = DEBUG_ALL || false;
- static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
- static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
@@ -283,8 +282,6 @@
static final boolean DEBUG_PSS = DEBUG_ALL || false;
static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
- static final boolean VALIDATE_TOKENS = false;
- static final boolean SHOW_ACTIVITY_START_TIME = true;
// Control over CPU and battery monitoring.
static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
@@ -1705,10 +1702,9 @@
case IMMERSIVE_MODE_LOCK_MSG: {
final boolean nextState = (msg.arg1 != 0);
if (mUpdateLock.isHeld() != nextState) {
- if (DEBUG_IMMERSIVE) {
- final ActivityRecord r = (ActivityRecord) msg.obj;
- Slog.d(TAG, "Applying new update lock state '" + nextState + "' for " + r);
- }
+ if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE,
+ "Applying new update lock state '" + nextState
+ + "' for " + (ActivityRecord)msg.obj);
if (nextState) {
mUpdateLock.acquire();
} else {
@@ -2480,15 +2476,15 @@
}
final void setFocusedActivityLocked(ActivityRecord r, String reason) {
- if (mFocusedActivity != r) {
- if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
+ if (r != null && mFocusedActivity != r) {
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
mFocusedActivity = r;
if (r.task != null && r.task.voiceInteractor != null) {
startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
} else {
finishRunningVoiceLocked();
}
- if (r != null && mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+ if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
applyUpdateLockStateLocked(r);
@@ -2505,7 +2501,7 @@
@Override
public void setFocusedStack(int stackId) {
- if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: stackId=" + stackId);
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedStack: stackId=" + stackId);
synchronized (ActivityManagerService.this) {
ActivityStack stack = mStackSupervisor.getStack(stackId);
if (stack != null) {
@@ -2587,7 +2583,7 @@
if (index > 0) {
index--;
}
- if (DEBUG_LRU) Slog.d(TAG, "Moving dep from " + lrui + " to " + index
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
+ " in LRU list: " + app);
mLruProcesses.add(index, app);
return index;
@@ -2633,13 +2629,13 @@
if (hasActivity) {
final int N = mLruProcesses.size();
if (N > 0 && mLruProcesses.get(N-1) == app) {
- if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top activity: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);
return;
}
} else {
if (mLruProcessServiceStart > 0
&& mLruProcesses.get(mLruProcessServiceStart-1) == app) {
- if (DEBUG_LRU) Slog.d(TAG, "Not moving, already top other: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
return;
}
}
@@ -2649,7 +2645,7 @@
if (app.persistent && lrui >= 0) {
// We don't care about the position of persistent processes, as long as
// they are in the list.
- if (DEBUG_LRU) Slog.d(TAG, "Not moving, persistent: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
return;
}
@@ -2718,27 +2714,29 @@
int nextIndex;
if (hasActivity) {
final int N = mLruProcesses.size();
- if (app.activities.size() == 0 && mLruProcessActivityStart < (N-1)) {
+ if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
// should always have a real activity).
- if (DEBUG_LRU) Slog.d(TAG, "Adding to second-top of LRU activity list: " + app);
- mLruProcesses.add(N-1, app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Adding to second-top of LRU activity list: " + app);
+ mLruProcesses.add(N - 1, app);
// To keep it from spamming the LRU list (by making a bunch of clients),
// we will push down any other entries owned by the app.
final int uid = app.info.uid;
- for (int i=N-2; i>mLruProcessActivityStart; i--) {
+ for (int i = N - 2; i > mLruProcessActivityStart; i--) {
ProcessRecord subProc = mLruProcesses.get(i);
if (subProc.info.uid == uid) {
// We want to push this one down the list. If the process after
// it is for the same uid, however, don't do so, because we don't
// want them internally to be re-ordered.
- if (mLruProcesses.get(i-1).info.uid != uid) {
- if (DEBUG_LRU) Slog.d(TAG, "Pushing uid " + uid + " swapping at " + i
- + ": " + mLruProcesses.get(i) + " : " + mLruProcesses.get(i-1));
+ if (mLruProcesses.get(i - 1).info.uid != uid) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Pushing uid " + uid + " swapping at " + i + ": "
+ + mLruProcesses.get(i) + " : " + mLruProcesses.get(i - 1));
ProcessRecord tmp = mLruProcesses.get(i);
- mLruProcesses.set(i, mLruProcesses.get(i-1));
- mLruProcesses.set(i-1, tmp);
+ mLruProcesses.set(i, mLruProcesses.get(i - 1));
+ mLruProcesses.set(i - 1, tmp);
i--;
}
} else {
@@ -2748,13 +2746,13 @@
}
} else {
// Process has activities, put it at the very tipsy-top.
- if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU activity list: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
mLruProcesses.add(app);
}
nextIndex = mLruProcessServiceStart;
} else if (hasService) {
// Process has services, put it at the top of the service list.
- if (DEBUG_LRU) Slog.d(TAG, "Adding to top of LRU service list: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
mLruProcesses.add(mLruProcessActivityStart, app);
nextIndex = mLruProcessServiceStart;
mLruProcessActivityStart++;
@@ -2765,7 +2763,7 @@
// If there is a client, don't allow the process to be moved up higher
// in the list than that client.
int clientIndex = mLruProcesses.lastIndexOf(client);
- if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG, "Unknown client " + client
+ if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG_LRU, "Unknown client " + client
+ " when updating " + app);
if (clientIndex <= lrui) {
// Don't allow the client index restriction to push it down farther in the
@@ -2776,7 +2774,7 @@
index = clientIndex;
}
}
- if (DEBUG_LRU) Slog.d(TAG, "Adding at " + index + " of LRU list: " + app);
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);
mLruProcesses.add(index, app);
nextIndex = index-1;
mLruProcessActivityStart++;
@@ -5599,7 +5597,7 @@
if (app.instrumentationClass != null) {
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
}
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config " + mConfiguration);
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
@@ -6137,8 +6135,7 @@
int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
Bundle options) {
- if (DEBUG_MU)
- Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
+ if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
ActivityRecord activity = null;
if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
activity = ActivityRecord.isInStackLocked(token);
@@ -8616,8 +8613,8 @@
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
- if (DEBUG_MU)
- Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+ if (DEBUG_MU) Slog.v(TAG_MU,
+ "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
int userId = app.userId;
if (providers != null) {
int N = providers.size();
@@ -8644,8 +8641,8 @@
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
- if (DEBUG_MU)
- Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
+ if (DEBUG_MU) Slog.v(TAG_MU,
+ "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
// Don't add this if it is a platform component that is marked
@@ -9174,10 +9171,9 @@
return null;
}
try {
- if (DEBUG_MU) {
- Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp="
- + cpr.launchingApp);
- }
+ if (DEBUG_MU) Slog.v(TAG_MU,
+ "Waiting to start provider " + cpr
+ + " launchingApp=" + cpr.launchingApp);
if (conn != null) {
conn.waiting = true;
}
@@ -9299,8 +9295,7 @@
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
- if (DEBUG_MU)
- Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
+ if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
@@ -9317,8 +9312,7 @@
continue;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
- if (DEBUG_MU)
- Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
+ if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
@@ -10400,9 +10394,7 @@
// update associated state if we're frontmost
if (r == mFocusedActivity) {
- if (DEBUG_IMMERSIVE) {
- Slog.d(TAG, "Frontmost changed immersion: "+ r);
- }
+ if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
applyUpdateLockStateLocked(r);
}
}
@@ -10751,7 +10743,8 @@
// This happens before any activities are started, so we can
// change mConfiguration in-place.
updateConfigurationLocked(configuration, null, false, true);
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Initial config: " + mConfiguration);
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Initial config: " + mConfiguration);
}
}
@@ -15094,10 +15087,9 @@
result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
|| (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
}
- if (DEBUG_MU) {
- Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo
- + ", " + className + ", 0x" + Integer.toHexString(flags) + ") = " + result);
- }
+ if (DEBUG_MU) Slog.v(TAG_MU,
+ "isSingleton(" + componentProcessName + ", " + aInfo + ", " + className + ", 0x"
+ + Integer.toHexString(flags) + ") = " + result);
return result;
}
@@ -16484,9 +16476,8 @@
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
if (changes != 0) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Slog.i(TAG, "Updating configuration to: " + values);
- }
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
+ "Updating configuration to: " + values);
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
@@ -16537,7 +16528,7 @@
ProcessRecord app = mLruProcesses.get(i);
try {
if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new config " + mConfiguration);
app.thread.scheduleConfigurationChanged(configCopy);
}
@@ -17740,15 +17731,15 @@
if (app.curAdj != app.setAdj) {
ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set " + app.pid + " " + app.processName +
- " adj " + app.curAdj + ": " + app.adjType);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
+ "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
+ + app.adjType);
app.setAdj = app.curAdj;
}
if (app.setSchedGroup != app.curSchedGroup) {
app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Setting process group of " + app.processName
+ " to " + app.curSchedGroup);
if (app.waitingToKill != null &&
@@ -17832,7 +17823,7 @@
}
}
if (app.setProcState != app.curProcState) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Proc state change of " + app.processName
+ " to " + app.curProcState);
boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
@@ -18097,7 +18088,7 @@
// step that cached level.
app.curRawAdj = curCachedAdj;
app.curAdj = app.modifyRawOomAdj(curCachedAdj);
- if (DEBUG_LRU && false) Slog.d(TAG, "Assigning activity LRU #" + i
+ if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+ " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
+ ")");
if (curCachedAdj != nextCachedAdj) {
@@ -18120,7 +18111,7 @@
// state is still as a service), which is what we want.
app.curRawAdj = curEmptyAdj;
app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
- if (DEBUG_LRU && false) Slog.d(TAG, "Assigning empty LRU #" + i
+ if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+ " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
+ ")");
if (curEmptyAdj != nextEmptyAdj) {
@@ -18210,13 +18201,13 @@
// We always allow the memory level to go up (better). We only allow it to go
// down if we are in a state where that is allowed, *and* the total number of processes
// has gone down since last time.
- if (DEBUG_OOM_ADJ) Slog.d(TAG, "oom: memFactor=" + memFactor + " last=" + mLastMemoryLevel
- + " allowLow=" + mAllowLowerMemLevel + " numProcs=" + mLruProcesses.size()
- + " last=" + mLastNumProcesses);
+ if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
+ + " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
+ + " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
if (memFactor > mLastMemoryLevel) {
if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
memFactor = mLastMemoryLevel;
- if (DEBUG_OOM_ADJ) Slog.d(TAG, "Keeping last mem factor!");
+ if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
}
}
mLastMemoryLevel = memFactor;
@@ -18256,9 +18247,8 @@
&& !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
- "Trimming memory of " + app.processName
- + " to " + curLevel);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
+ "Trimming memory of " + app.processName + " to " + curLevel);
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
@@ -18293,7 +18283,7 @@
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of heavy-weight " + app.processName
+ " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
app.thread.scheduleTrimMemory(
@@ -18311,7 +18301,7 @@
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
if (app.trimMemoryLevel < level && app.thread != null) {
try {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of bg-ui " + app.processName
+ " to " + level);
app.thread.scheduleTrimMemory(level);
@@ -18322,7 +18312,7 @@
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of fg " + app.processName
+ " to " + fgTrimLevel);
app.thread.scheduleTrimMemory(fgTrimLevel);
@@ -18348,7 +18338,7 @@
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Trimming memory of ui hidden " + app.processName
+ " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
app.thread.scheduleTrimMemory(
@@ -18383,12 +18373,12 @@
}
if (DEBUG_OOM_ADJ) {
+ final long duration = SystemClock.uptimeMillis() - now;
if (false) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms", here);
+ Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
+ new RuntimeException("here").fillInStackTrace());
} else {
- Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms");
+ Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ca2721c..d34b33b 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -76,6 +76,7 @@
final class ActivityRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+ private static final boolean SHOW_ACTIVITY_START_TIME = true;
static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
@@ -939,7 +940,7 @@
final long thisTime = curTime - fullyDrawnStartTime;
final long totalTime = stack.mFullyDrawnStartTime != 0
? (curTime - stack.mFullyDrawnStartTime) : thisTime;
- if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
+ if (SHOW_ACTIVITY_START_TIME) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME,
userId, System.identityHashCode(this), shortComponentName,
@@ -973,7 +974,7 @@
final long thisTime = curTime - displayStartTime;
final long totalTime = stack.mLaunchStartTime != 0
? (curTime - stack.mLaunchStartTime) : thisTime;
- if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
+ if (SHOW_ACTIVITY_START_TIME) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
userId, System.identityHashCode(this), shortComponentName,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 456ed33..4bb265d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
@@ -26,7 +25,6 @@
import static com.android.server.am.ActivityManagerService.DEBUG_TRANSITION;
import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
-import static com.android.server.am.ActivityManagerService.VALIDATE_TOKENS;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -97,6 +95,9 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+
+ private static final boolean VALIDATE_TOKENS = false;
// Ticks during which we check progress while waiting for an app to launch.
static final int LAUNCH_TICK = 500;
@@ -507,6 +508,8 @@
mStacks.remove(this);
mStacks.add(this);
}
+ // TODO(multi-display): Focus stack currently adjusted in call to move home stack.
+ // Needs to also work if focus is moving to the non-home display.
if (isOnHomeDisplay()) {
mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
}
@@ -2573,7 +2576,11 @@
}
// Move the home stack to the top if this stack is fullscreen or there is no
// other visible stack.
- mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), myReason);
+ if (mStackSupervisor.moveHomeStackTaskToTop(
+ task.getTaskToReturnTo(), myReason)) {
+ // Activity focus was already adjusted. Nothing else to do...
+ return;
+ }
}
}
@@ -3575,7 +3582,6 @@
mTaskHistory.remove(taskNdx);
mTaskHistory.add(top, task);
updateTaskMovement(task, true);
- mWindowManager.moveTaskToTop(task.taskId);
return;
}
}
@@ -3600,12 +3606,14 @@
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
insertTaskAtTop(tr);
- moveToFront(reason);
+
+ // Set focus to the top running activity of this stack.
+ ActivityRecord r = topRunningActivityLocked(null);
+ mService.setFocusedActivityLocked(r, reason);
if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
if (noAnimation) {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
- ActivityRecord r = topRunningActivityLocked(null);
if (r != null) {
mNoAnimActivities.add(r);
}
@@ -3740,12 +3748,12 @@
final boolean ensureActivityConfigurationLocked(ActivityRecord r,
int globalChanges) {
if (mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Skipping config check (will change): " + r);
return true;
}
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Ensuring correct configuration: " + r);
// Make sure the current stack override configuration is supported by the top task
@@ -3758,7 +3766,7 @@
mWindowManager.forceStackToFullscreen(mStackId, !topTask.mResizeable);
updateOverrideConfiguration(newOverrideConfig);
mForcedFullscreen = !prevFullscreen && mFullscreen;
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Updated stack config to support task=" + topTask
+ " resizeable=" + topTask.mResizeable
+ " mForcedFullscreen=" + mForcedFullscreen
@@ -3772,14 +3780,14 @@
if (r.configuration == newConfig
&& r.stackConfigOverride == mOverrideConfig
&& !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration unchanged in " + r);
return true;
}
// We don't worry about activities that are finishing.
if (r.finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration doesn't matter in finishing " + r);
r.stopFreezingScreenLocked(false);
return true;
@@ -3813,7 +3821,7 @@
}
final int changes = oldConfig.diff(newConfig) | stackChanges;
if (changes == 0 && !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration no differences in " + r);
return true;
}
@@ -3821,7 +3829,7 @@
// If the activity isn't currently running, just leave the new
// configuration and it will pick that up next time it starts.
if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration doesn't matter not running " + r);
r.stopFreezingScreenLocked(false);
r.forceNewConfig = false;
@@ -3829,26 +3837,25 @@
}
// Figure out how to handle the changes between the configurations.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.getRealConfigChanged())
- + ", newConfig=" + newConfig);
- }
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Checking to restart " + r.info.name + ": changed=0x"
+ + Integer.toHexString(changes) + ", handles=0x"
+ + Integer.toHexString(r.info.getRealConfigChanged()) + ", newConfig=" + newConfig);
+
if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
r.configChangeFlags |= changes;
r.startFreezingScreenLocked(r.app, globalChanges);
r.forceNewConfig = false;
if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is destroying non-running " + r);
destroyActivityLocked(r, true, "config");
} else if (r.state == ActivityState.PAUSING) {
// A little annoying: we are waiting for this activity to
// finish pausing. Let's not do anything now, but just
// flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is skipping already pausing " + r);
r.configDestroy = true;
return true;
@@ -3857,12 +3864,12 @@
// and we need to restart the top, resumed activity.
// Instead of doing the normal handshaking, just say
// "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, true);
r.configChangeFlags = 0;
} else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching non-resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, false);
r.configChangeFlags = 0;
@@ -3879,7 +3886,7 @@
// system level configuration it last got.
if (r.app != null && r.app.thread != null) {
try {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending new config to " + r);
r.app.thread.scheduleActivityConfigurationChanged(
r.appToken, new Configuration(mOverrideConfig));
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f56f65f..4bab4fd 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,12 +17,12 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
@@ -117,6 +117,8 @@
public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
static final boolean DEBUG = DEBUG_ALL || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
@@ -441,13 +443,21 @@
}
}
- void moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
+ /** Returns true if the focus activity was adjusted to the home stack top activity. */
+ boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
mWindowManager.showRecentApps();
- return;
+ return false;
}
- moveHomeStack(true, reason);
+
mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
+
+ final ActivityRecord top = mHomeStack.topRunningActivityLocked(null);
+ if (top == null) {
+ return false;
+ }
+ mService.setFocusedActivityLocked(top, reason);
+ return true;
}
boolean resumeHomeStackTask(int homeStackTaskType, ActivityRecord prev, String reason) {
@@ -460,14 +470,13 @@
mWindowManager.showRecentApps();
return false;
}
- moveHomeStackTaskToTop(homeStackTaskType, reason);
+
if (prev != null) {
prev.task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
}
ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
- // if (r != null && (r.isHomeActivity() || r.isRecentsActivity())) {
- if (r != null && r.isHomeActivity()) {
+ if (r != null) {
mService.setFocusedActivityLocked(r, reason);
return resumeTopActivitiesLocked(mHomeStack, prev, null);
}
@@ -908,7 +917,7 @@
stack = container.mStack;
}
stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
- if (DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Starting activity when config will change = " + stack.mConfigWillChange);
final long origId = Binder.clearCallingIdentity();
@@ -998,7 +1007,7 @@
mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
stack.mConfigWillChange = false;
- if (DEBUG_CONFIGURATION) Slog.v(TAG,
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
mService.updateConfigurationLocked(config, null, false, false);
}
@@ -1575,10 +1584,11 @@
stack = task.stack;
if (stack.isOnHomeDisplay()) {
if (mFocusedStack != stack) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: Setting " +
- "focused stack to r=" + r + " task=" + task);
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+ "computeStackFocus: Setting " + "focused stack to r=" + r
+ + " task=" + task);
} else {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Focused stack already=" + mFocusedStack);
}
}
@@ -1594,7 +1604,7 @@
if (mFocusedStack != mHomeStack && (!newTask ||
mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Have a focused stack=" + mFocusedStack);
return mFocusedStack;
}
@@ -1603,7 +1613,7 @@
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
if (!stack.isHomeStack()) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Setting focused stack=" + stack);
return stack;
}
@@ -1611,8 +1621,8 @@
// Need to create an app stack for this user.
stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: New stack r=" + r +
- " stackId=" + stack.mStackId);
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ + r + " stackId=" + stack.mStackId);
return stack;
}
return mHomeStack;
@@ -1874,11 +1884,6 @@
if (r.task == null) {
r.task = intentActivity.task;
}
- targetStack = intentActivity.task.stack;
- targetStack.mLastPausedActivity = null;
- if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
- + " from " + intentActivity);
- targetStack.moveToFront("intentActivityFound");
if (intentActivity.task.intent == null) {
// This task was started because of movement of
// the activity based on affinity... now that we
@@ -1886,29 +1891,31 @@
// base intent.
intentActivity.task.setIntent(r);
}
+ targetStack = intentActivity.task.stack;
+ targetStack.mLastPausedActivity = null;
// If the target task is not in the front, then we need
// to bring it to the front... except... well, with
// SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
// to have the same behavior as if a new instance was
// being started, which means not bringing it to the front
// if the caller is not itself in the front.
- final ActivityStack lastStack = getLastStack();
- ActivityRecord curTop = lastStack == null?
- null : lastStack.topRunningNonDelayedActivityLocked(notTop);
+ final ActivityStack focusStack = getFocusedStack();
+ ActivityRecord curTop = (focusStack == null)
+ ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
boolean movedToFront = false;
if (curTop != null && (curTop.task != intentActivity.task ||
- curTop.task != lastStack.topTask())) {
+ curTop.task != focusStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
- // We really do want to push this one into the
- // user's face, right now.
+ // We really do want to push this one into the user's face, right now.
if (launchTaskBehind && sourceRecord != null) {
intentActivity.setTaskToAffiliateWith(sourceRecord.task);
}
movedHome = true;
targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
options, "bringingFoundTaskToFront");
+ movedToFront = true;
if ((launchFlags &
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
@@ -1916,9 +1923,14 @@
intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
}
options = null;
- movedToFront = true;
}
}
+ if (!movedToFront) {
+ if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
+ + " from " + intentActivity);
+ targetStack.moveToFront("intentActivityFound");
+ }
+
// If the caller has requested that the target task be
// reset, then do so.
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1943,15 +1955,15 @@
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
}
if ((launchFlags &
- (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))
- == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {
+ (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any
// existing task with its new activity. Well that should
// not be too hard...
reuseTask = intentActivity.task;
reuseTask.performClearTaskLocked();
reuseTask.setIntent(r);
- } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
+ } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| launchSingleInstance || launchSingleTask) {
// In this situation we want to remove all activities
// from the task up to the one being started. In most
@@ -2120,8 +2132,8 @@
}
if (!movedHome) {
if ((launchFlags &
- (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
- == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
+ (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity, so before starting
// their own activity we will bring home to the front.
r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index ce63d75..0fe9231 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -46,7 +46,7 @@
public final class CompatModePackages {
private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
- private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private final ActivityManagerService mService;
private final AtomicFile mFile;
@@ -334,7 +334,7 @@
}
try {
if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new compat " + ci);
app.thread.updatePackageCompatibilityInfo(packageName, ci);
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index fcdd9d9..f05e6aa 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -653,6 +653,7 @@
return;
} else {
mFocusFollowers.add(ff);
+ notifyExtPolicyCurrentFocusAsync(ff);
}
}
}
@@ -672,6 +673,32 @@
}
/**
+ * @param pcb non null
+ */
+ void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) {
+ final IAudioPolicyCallback pcb2 = pcb;
+ final Thread thread = new Thread() {
+ @Override
+ public void run() {
+ synchronized(mAudioFocusLock) {
+ if (mFocusStack.isEmpty()) {
+ return;
+ }
+ try {
+ pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(),
+ // top of focus stack always has focus
+ AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
+ + pcb2.asBinder(), e);
+ }
+ }
+ }
+ };
+ thread.start();
+ }
+
+ /**
* Called synchronized on mAudioFocusLock
*/
void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
@@ -680,7 +707,7 @@
// oneway
pcb.notifyAudioFocusGrant(afi, requestResult);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
+ Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
+ pcb.asBinder(), e);
}
}
@@ -695,7 +722,7 @@
// oneway
pcb.notifyAudioFocusLoss(afi, wasDispatched);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
+ Log.e(TAG, "Can't call notifyAudioFocusLoss() on IAudioPolicyCallback "
+ pcb.asBinder(), e);
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0c7d71b..9ccb2ea 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -18,10 +18,12 @@
import android.app.ActivityManager;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -51,6 +53,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -74,6 +77,7 @@
private final UserProfiles mUserProfiles;
private final SettingsObserver mSettingsObserver;
private final Config mConfig;
+ private ArraySet<String> mRestored;
// contains connections to all connected services, including app services
// and system services
@@ -91,6 +95,8 @@
// user change).
private int[] mLastSeenProfileIds;
+ private final BroadcastReceiver mRestoreReceiver;
+
public ManagedServices(Context context, Handler handler, Object mutex,
UserProfiles userProfiles) {
mContext = context;
@@ -98,6 +104,24 @@
mUserProfiles = userProfiles;
mConfig = getConfig();
mSettingsObserver = new SettingsObserver(handler);
+
+ mRestoreReceiver = new SettingRestoredReceiver();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
+ context.registerReceiver(mRestoreReceiver, filter);
+ }
+
+ class SettingRestoredReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
+ String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+ if (Objects.equals(element, mConfig.secureSettingName)) {
+ String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+ String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
+ settingRestored(element, prevValue, newValue, getSendingUserId());
+ }
+ }
+ }
}
abstract protected Config getConfig();
@@ -140,6 +164,31 @@
}
}
+ // By convention, restored settings are replicated to another settings
+ // entry, named similarly but with a disambiguation suffix.
+ public static final String restoredSettingName(Config config) {
+ return config.secureSettingName + ":restored";
+ }
+
+ // The OS has done a restore of this service's saved state. We clone it to the
+ // 'restored' reserve, and then once we return and the actual write to settings is
+ // performed, our observer will do the work of maintaining the restored vs live
+ // settings data.
+ public void settingRestored(String element, String oldValue, String newValue, int userid) {
+ if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
+ + " ovalue=" + oldValue + " nvalue=" + newValue);
+ if (mConfig.secureSettingName.equals(element)) {
+ if (element != null) {
+ mRestored = null;
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ restoredSettingName(mConfig),
+ newValue,
+ userid);
+ disableNonexistentServices(userid);
+ }
+ }
+ }
+
public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
+ " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
@@ -211,8 +260,23 @@
}
private void disableNonexistentServices(int userId) {
+ final ContentResolver cr = mContext.getContentResolver();
+ boolean restoredChanged = false;
+ if (mRestored == null) {
+ String restoredSetting = Settings.Secure.getStringForUser(
+ cr,
+ restoredSettingName(mConfig),
+ userId);
+ if (!TextUtils.isEmpty(restoredSetting)) {
+ if (DEBUG) Slog.d(TAG, "restored: " + restoredSetting);
+ String[] restored = restoredSetting.split(ENABLED_SERVICES_SEPARATOR);
+ mRestored = new ArraySet<String>(Arrays.asList(restored));
+ } else {
+ mRestored = new ArraySet<String>();
+ }
+ }
String flatIn = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ cr,
mConfig.secureSettingName,
userId);
if (!TextUtils.isEmpty(flatIn)) {
@@ -228,14 +292,16 @@
ResolveInfo resolveInfo = installedServices.get(i);
ServiceInfo info = resolveInfo.serviceInfo;
+ ComponentName component = new ComponentName(info.packageName, info.name);
if (!mConfig.bindPermission.equals(info.permission)) {
Slog.w(TAG, "Skipping " + getCaption() + " service "
+ info.packageName + "/" + info.name
+ ": it does not require the permission "
+ mConfig.bindPermission);
+ restoredChanged |= mRestored.remove(component.flattenToString());
continue;
}
- installed.add(new ComponentName(info.packageName, info.name));
+ installed.add(component);
}
String flatOut = "";
@@ -246,16 +312,27 @@
ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
if (installed.contains(enabledComponent)) {
remaining.add(enabled[i]);
+ restoredChanged |= mRestored.remove(enabled[i]);
}
}
+ remaining.addAll(mRestored);
flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining);
}
if (DEBUG) Slog.v(TAG, "flat after: " + flatOut);
if (!flatIn.equals(flatOut)) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(cr,
mConfig.secureSettingName,
flatOut, userId);
}
+ if (restoredChanged) {
+ if (DEBUG) Slog.d(TAG, "restored changed; rewriting");
+ final String flatRestored = TextUtils.join(ENABLED_SERVICES_SEPARATOR,
+ mRestored.toArray());
+ Settings.Secure.putStringForUser(cr,
+ restoredSettingName(mConfig),
+ flatRestored,
+ userId);
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b789d41..dfac6cf 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -176,6 +176,9 @@
static final int DOUBLE_TAP_HOME_NOTHING = 0;
static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
+ static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;
+ static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1;
+
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
static final int APPLICATION_PANEL_SUBLAYER = 1;
@@ -371,6 +374,7 @@
int mLongPressOnPowerBehavior;
int mDoublePressOnPowerBehavior;
int mTriplePressOnPowerBehavior;
+ int mShortPressOnSleepBehavior;
boolean mAwake;
boolean mScreenOnEarly;
boolean mScreenOnFully;
@@ -1057,6 +1061,20 @@
}
}
+ private void sleepPress(KeyEvent event) {
+ switch (mShortPressOnSleepBehavior) {
+ case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
+ mPowerManager.goToSleep(event.getEventTime(),
+ PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ break;
+ case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
+ launchHomeFromHotKey(false /* awakenDreams */);
+ mPowerManager.goToSleep(event.getEventTime(),
+ PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ break;
+ }
+ }
+
private int getResolvedLongPressOnPowerBehavior() {
if (FactoryTest.isLongPressOnPowerOffEnabled()) {
return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
@@ -1321,6 +1339,8 @@
com.android.internal.R.integer.config_doublePressOnPowerBehavior);
mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
+ mShortPressOnSleepBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortPressOnSleepBehavior);
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
@@ -3028,11 +3048,15 @@
}
}
+ void launchHomeFromHotKey() {
+ launchHomeFromHotKey(true /* awakenFromDreams */);
+ }
+
/**
* A home key -> launch home action was detected. Take the appropriate action
* given the situation with the keyguard.
*/
- void launchHomeFromHotKey() {
+ void launchHomeFromHotKey(final boolean awakenFromDreams) {
if (isKeyguardShowingAndNotOccluded()) {
// don't launch home if keyguard showing
} else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
@@ -3047,7 +3071,7 @@
} catch (RemoteException e) {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
- startDockOrHome(true /*fromHomeKey*/);
+ startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}
}
});
@@ -3059,13 +3083,15 @@
}
if (mRecentsVisible) {
// Hide Recents and notify it to launch Home
- awakenDreams();
+ if (awakenFromDreams) {
+ awakenDreams();
+ }
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
hideRecentApps(false, true);
} else {
// Otherwise, just launch Home
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
- startDockOrHome(true /*fromHomeKey*/);
+ startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}
}
}
@@ -4712,12 +4738,11 @@
case KeyEvent.KEYCODE_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
+ isWakeKey = false;
if (!mPowerManager.isInteractive()) {
useHapticFeedback = false; // suppress feedback if already non-interactive
}
- mPowerManager.goToSleep(event.getEventTime(),
- PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
- isWakeKey = false;
+ sleepPress(event);
break;
}
@@ -5897,8 +5922,10 @@
return null;
}
- void startDockOrHome(boolean fromHomeKey) {
- awakenDreams();
+ void startDockOrHome(boolean fromHomeKey, boolean awakenFromDreams) {
+ if (awakenFromDreams) {
+ awakenDreams();
+ }
Intent dock = createHomeDockIntent();
if (dock != null) {
@@ -5936,7 +5963,7 @@
} catch (RemoteException e) {
}
sendCloseSystemWindows();
- startDockOrHome(false /*fromHomeKey*/);
+ startDockOrHome(false /*fromHomeKey*/, true /* awakenFromDreams */);
} else {
// This code brings home to the front or, if it is already
// at the front, puts the device to sleep.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 66c2f5f..9e373b7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1080,6 +1080,9 @@
case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
break;
+ case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON:
+ Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")...");
+ break;
case PowerManager.GO_TO_SLEEP_REASON_HDMI:
Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
break;
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 8192b5f..4acbd1c 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -39,6 +39,8 @@
import java.io.File;
+import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext;
+
/**
* Custom implementation of {@link LayoutInflater} to handle custom views.
*/
@@ -60,7 +62,12 @@
protected BridgeInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
- mProjectCallback = null;
+ newContext = getBaseContext(newContext);
+ if (newContext instanceof BridgeContext) {
+ mProjectCallback = ((BridgeContext) newContext).getProjectCallback();
+ } else {
+ mProjectCallback = null;
+ }
}
/**
@@ -154,9 +161,7 @@
@Override
public View inflate(int resource, ViewGroup root) {
Context context = getContext();
- while (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
+ context = getBaseContext(context);
if (context instanceof BridgeContext) {
BridgeContext bridgeContext = (BridgeContext)context;
@@ -219,9 +224,7 @@
private void setupViewInContext(View view, AttributeSet attrs) {
Context context = getContext();
- while (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
+ context = getBaseContext(context);
if (context instanceof BridgeContext) {
BridgeContext bc = (BridgeContext) context;
// get the view key
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index dafc96b..08a97d6 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -48,9 +48,7 @@
AttributeSet attrs) {
if (menuItem instanceof BridgeMenuItemImpl) {
Context context = thisInflater.getContext();
- while (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
+ context = BridgeContext.getBaseContext(context);
if (context instanceof BridgeContext) {
Object viewKey = BridgeInflater.getViewKeyFromParser(
attrs, ((BridgeContext) context), null, false);
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
index 3915046..82ae1df 100644
--- a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -122,9 +122,7 @@
@NonNull
private static DisplayMetrics getMetrics(View view) {
Context context = view.getContext();
- while (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
+ context = BridgeContext.getBaseContext(context);
if (context instanceof BridgeContext) {
return ((BridgeContext) context).getMetrics();
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index 8d1d0c1..bb95c4e 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -19,7 +19,6 @@
import com.android.layoutlib.bridge.android.BridgeContext;
import android.content.Context;
-import android.view.ContextThemeWrapper;
import android.view.View;
/**
@@ -42,9 +41,7 @@
CharSequence title, int showAsAction) {
super(menu, group, id, categoryOrder, ordering, title, showAsAction);
Context context = menu.getContext();
- while (context instanceof ContextThemeWrapper) {
- context = ((ContextThemeWrapper) context).getBaseContext();
- }
+ context = BridgeContext.getBaseContext(context);
if (context instanceof BridgeContext) {
mContext = ((BridgeContext) context);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 179a8e7..e1c58fd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -40,6 +40,7 @@
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -963,6 +964,13 @@
return defValue;
}
+ public static Context getBaseContext(Context context) {
+ while (context instanceof ContextWrapper) {
+ context = ((ContextWrapper) context).getBaseContext();
+ }
+ return context;
+ }
+
//------------ NOT OVERRIDEN --------------------
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
index e5023b8..ee57067 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -21,11 +21,15 @@
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
+import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -55,7 +59,7 @@
View contentView = getDecorContent().findViewById(contentRootId);
if (contentView != null) {
assert contentView instanceof FrameLayout;
- setContentRoot(((FrameLayout) contentView));
+ setContentRoot((FrameLayout) contentView);
} else {
// Something went wrong. Create a new FrameLayout in the enclosing layout.
FrameLayout contentRoot = new FrameLayout(context);
@@ -85,6 +89,27 @@
}
@Override
+ protected LayoutInflater getInflater(BridgeContext context) {
+ // Other than the resource resolution part, the code has been taken from the support
+ // library. see code from line 269 onwards in
+ // https://android.googlesource.com/platform/frameworks/support/+/android-5.1.0_r1/v7/appcompat/src/android/support/v7/app/ActionBarActivityDelegateBase.java
+ Context themedContext = context;
+ RenderResources resources = context.getRenderResources();
+ ResourceValue actionBarTheme = resources.findItemInTheme("actionBarTheme", false);
+ if (actionBarTheme != null) {
+ // resolve it, if needed.
+ actionBarTheme = resources.resolveResValue(actionBarTheme);
+ }
+ if (actionBarTheme instanceof StyleResourceValue) {
+ int styleId = context.getDynamicIdByStyle(((StyleResourceValue) actionBarTheme));
+ if (styleId != 0) {
+ themedContext = new ContextThemeWrapper(context, styleId);
+ }
+ }
+ return LayoutInflater.from(themedContext);
+ }
+
+ @Override
protected void setTitle(CharSequence title) {
if (title != null && mWindowDecorActionBar != null) {
Method setTitle = getMethod(mWindowActionBarClass, "setTitle", CharSequence.class);
@@ -104,8 +129,8 @@
protected void setIcon(String icon) {
// Do this only if the action bar doesn't already have an icon.
if (icon != null && !icon.isEmpty() && mWindowDecorActionBar != null) {
- if (((Boolean) invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar)
- )) {
+ if (invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar)
+ == Boolean.TRUE) {
Drawable iconDrawable = getDrawable(icon, false);
if (iconDrawable != null) {
Method setIcon = getMethod(mWindowActionBarClass, "setIcon", Drawable.class);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
index b29d25f..2a83ea1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
@@ -44,6 +44,7 @@
private final View mDecorContent;
private final ActionBarCallback mCallback;
+ @SuppressWarnings("NullableProblems") // Should be initialized by subclasses.
@NonNull private FrameLayout mContentRoot;
public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
@@ -80,7 +81,7 @@
}
// Inflate action bar layout.
- mDecorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
+ mDecorContent = getInflater(context).inflate(layoutId, mEnclosingLayout, true);
}
@@ -91,7 +92,11 @@
*/
protected abstract ResourceValue getLayoutResource(BridgeContext context);
- protected void setContentRoot(FrameLayout contentRoot) {
+ protected LayoutInflater getInflater(BridgeContext context) {
+ return LayoutInflater.from(context);
+ }
+
+ protected void setContentRoot(@NonNull FrameLayout contentRoot) {
mContentRoot = contentRoot;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index c9aa400..7c11284d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -1128,8 +1128,7 @@
}
} else {
// action bar overrides title bar so only look for this one if action bar is hidden
- boolean windowNoTitle = getBooleanThemeValue(resources,
- "windowNoTitle", false, !isThemeAppCompat(resources));
+ boolean windowNoTitle = getBooleanThemeValue(resources, "windowNoTitle", false, true);
if (!windowNoTitle) {