Android 螢幕旋轉事件流程分析
阿新 • • 發佈:2019-01-23
WindowManagerService.java (android-6.0\frameworks\base\services\core\java\com\android\server\wm)
[java] view plain copy print?
[java] view plain copy print?
[java] view plain copy print?
[java] view plain copy print?
- privatevoid initPolicy() {
- UiThread.getHandler().runWithScissors(new Runnable() {
- @Override
- publicvoid run() {
- WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
- mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
- }
- }, 0);
- }
在WMS構造方法中就呼叫initPolicy方法。在這個方法中,很明顯是在初始化mPolicy:WindowManagerPolicy這個變數。 在WMS中,該變數實質是PhoneWindowManager物件。PhoneWindowManager類實現了WindowManagerPolicy介面類。 PhoneWindowManager.java (android-6.0\frameworks\base\services\core\java\com\android\server\policy) [java] view plain copy print?private void initPolicy() { UiThread.getHandler().runWithScissors(new Runnable() { @Override public void run() { WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper()); mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this); } }, 0); }
- /** {@inheritDoc} */
- @Override
- publicvoid init(Context context, IWindowManager windowManager,
- WindowManagerFuncs windowManagerFuncs) {
- mContext = context;
- mWindowManager = windowManager;
- mWindowManagerFuncs = windowManagerFuncs;
- mOrientationListener = new MyOrientationListener(mContext, mHandler);
- try {
- mOrientationListener.setCurrentRotation(windowManager.getRotation());
- } catch (RemoteException ex) { }
- }
/** {@inheritDoc} */
@Override
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
mOrientationListener = new MyOrientationListener(mContext, mHandler);
try {
mOrientationListener.setCurrentRotation(windowManager.getRotation());
} catch (RemoteException ex) { }
}
發現在初始化的過程中,例項化一個方位監聽物件MyOrientationListener,並且給它設定了初始值。該初始值從WMS中獲取,預設為0。
MyOrientationListener類是PhoneWindowManager的一個內部類,它繼承了WindowOrientationListener類。
WindowOrientationListener.java (android-6.0\frameworks\base\services\core\java\com\android\server\policy)
[java] view plain copy print?- private WindowOrientationListener(Context context, Handler handler, int rate) {
- mHandler = handler;
- mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
- mRate = rate;
- mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
- ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
- if (mSensor != null) {
- // Create listener only if sensors do exist
- mSensorEventListener = new SensorEventListenerImpl(context);
- }
- }
private WindowOrientationListener(Context context, Handler handler, int rate) {
mHandler = handler;
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
if (mSensor != null) {
// Create listener only if sensors do exist
mSensorEventListener = new SensorEventListenerImpl(context);
}
}
看到這邊,一下子就明白旋屏事件上報的大致流程。首先由感測器計算資料確認是否上報,然後通過Handler或者回調方法來處理。這麼想是因為構造器中傳遞進來一個Handler物件,另外本身就是通過其子類呼叫才進入WindowOrientationListener。具體是怎麼一個流程,還要分析接下來的程式碼。
在這裡,預設採用的感測器是加速度感測器,USE_GRAVITY_SENSOR:false
在Android7.0中,預設採用的是方向感測器。
WindowOrientationListener構造器中,mSensorManager、mSensor、mSensorEventListener物件。在後面的enable方法中,通過mSensorManager呼叫registerListener為mSensor註冊監聽事件mSensorEventListener。
[java] view plain copy print?- * Enables the WindowOrientationListener so it will monitor the sensor and call
- * {@link #onProposedRotationChanged(int)} when the device orientation changes.
- */
- publicvoid enable() {
- mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
- mEnabled = true;
- }
- }
- }
* Enables the WindowOrientationListener so it will monitor the sensor and call
* {@link #onProposedRotationChanged(int)} when the device orientation changes.
*/
public void enable() {
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
mEnabled = true;
}
}
}
這裡不關注這些個點,還是去看感測器監聽處理這一塊內容。
SensorEventListenerImpl是WindowOrientationListener的內部類,它實現了介面。
@Override
[java] view plain copy print?- publicvoid onSensorChanged(SensorEvent event) {
- int proposedRotation;
- int oldProposedRotation;
- synchronized (mLock) {
- // The vector given in the SensorEvent points straight up (towards the sky) under
- // ideal conditions (the phone is not accelerating). I’ll call this up vector
- // elsewhere.
- float x = event.values[ACCELEROMETER_DATA_X];
- float y = event.values[ACCELEROMETER_DATA_Y];
- float z = event.values[ACCELEROMETER_DATA_Z];
- }
- }
- // Tell the listener.
- if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
- if (LOG) {
- Slog.v(TAG, ”Proposed rotation changed! proposedRotation=” + proposedRotation
- + ”, oldProposedRotation=” + oldProposedRotation);
- }
- onProposedRotationChanged(proposedRotation);
- }
- }
public void onSensorChanged(SensorEvent event) {
int proposedRotation;
int oldProposedRotation;
synchronized (mLock) {
// The vector given in the SensorEvent points straight up (towards the sky) under
// ideal conditions (the phone is not accelerating). I'll call this up vector
// elsewhere.
float x = event.values[ACCELEROMETER_DATA_X];
float y = event.values[ACCELEROMETER_DATA_Y];
float z = event.values[ACCELEROMETER_DATA_Z];
}
}
// Tell the listener.
if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
if (LOG) {
Slog.v(TAG, "Proposed rotation changed! proposedRotation=" + proposedRotation
+ ", oldProposedRotation=" + oldProposedRotation);
}
onProposedRotationChanged(proposedRotation);
}
}
感測器資料計算過程這裡省略了,在onSensorChanged方法的最後通過函式回撥上報旋屏事件。回顧上面的內容,驗證的確如此。
[java] view plain copy print?- /**
- * Called when the rotation view of the device has changed.
- *
- * This method is called whenever the orientation becomes certain of an orientation.
- * It is called each time the orientation determination transitions from being
- * uncertain to being certain again, even if it is the same orientation as before.
- *
- * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
- * @see android.view.Surface
- */
- publicabstractvoid onProposedRotationChanged(int rotation);
/**
* Called when the rotation view of the device has changed.
*
* This method is called whenever the orientation becomes certain of an orientation.
* It is called each time the orientation determination transitions from being
* uncertain to being certain again, even if it is the same orientation as before.
*
* @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
* @see android.view.Surface
*/
public abstract void onProposedRotationChanged(int rotation);
onProposedRotationChanged方法是宣告在WindowOrientationListener類的一個抽象方法,它具體實現在PhoneWindowManager的一個內部類,即MyOrientationListener。
PhoneWindowManager.java (android-6.0\frameworks\base\services\core\java\com\android\server\policy)
[java] view plain copy print?- @Override
- publicvoid onProposedRotationChanged(int rotation) {
- if (localLOGV) Slog.v(TAG, “onProposedRotationChanged, rotation=” + rotation);
- updateRotation(false);
- }
@Override
public void onProposedRotationChanged(int rotation) {
if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
updateRotation(false);
}
[java] view plain copy print?
- void updateRotation(boolean alwaysSendConfiguration) {
- try {
- //set orientation on WindowManager
- mWindowManager.updateRotation(alwaysSendConfiguration, false); //false、false
- } catch (RemoteException e) {
- // Ignore
- }
- }
void updateRotation(boolean alwaysSendConfiguration) {
try {
//set orientation on WindowManager
mWindowManager.updateRotation(alwaysSendConfiguration, false); //false、false
} catch (RemoteException e) {
// Ignore
}
}
很明顯,是通知WMS更新rotation。
WindowManagerService.java (android-6.0\frameworks\base\services\core\java\com\android\server\wm)
[java] view plain copy print?- /**
- * Recalculate the current rotation.
- *
- * Called by the window manager policy whenever the state of the system changes
- * such that the current rotation might need to be updated, such as when the
- * device is docked or rotated into a new posture.
- */
- @Override
- publicvoid updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
- updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
- }
/**
* Recalculate the current rotation.
*
* Called by the window manager policy whenever the state of the system changes
* such that the current rotation might need to be updated, such as when the
* device is docked or rotated into a new posture.
*/
@Override
public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
}
[java] view plain copy print?
- publicvoid updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
- boolean changed;
- synchronized(mWindowMap) {
- changed = updateRotationUncheckedLocked(false);
- if (changed || alwaysSendConfiguration) {
- sendNewConfiguration();
- }
- }
public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
boolean changed;
synchronized(mWindowMap) {
changed = updateRotationUncheckedLocked(false);
if (changed || alwaysSendConfiguration) {
sendNewConfiguration();
}
}
一般情況,rotation都是發生變化的,也就是說updateRotationUncheckedLocked返回值通常為true,故會呼叫sendNewConfiguration。
[java] view plain copy print?- /*
- * Instruct the Activity Manager to fetch the current configuration and broadcast
- * that to config-changed listeners if appropriate.
- */
- void sendNewConfiguration() {
- try {
- mActivityManager.updateConfiguration(null);
- } catch (RemoteException e) {
- }
- }
/*
* Instruct the Activity Manager to fetch the current configuration and broadcast
* that to config-changed listeners if appropriate.
*/
void sendNewConfiguration() {
try {
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
mActivityManager本質是AMS Server端,這裡從WMS執行至AMS,
ActivityManagerService.java (android-6.0\frameworks\base\services\core\java\com\android\server\am)
[java] view plain copy print?- publicvoid updateConfiguration(Configuration values) {
- enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
- ”updateConfiguration()”);
- synchronized(this) {
- if (values == null && mWindowManager != null) {
- // sentinel: fetch the current configuration from the window manager
- values = mWindowManager.computeNewConfiguration();
- }
- updateConfigurationLocked(values, null, false, false);
- }
- }
public void updateConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
synchronized(this) {
if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration();
}
updateConfigurationLocked(values, null, false, false);
}
}
AMS中,第一步:檢查許可權,沒有許可權則拋一個異常;第二步:從WMS中獲取Configuration值;第三步:去真正更新Configuration值。
[java] view plain copy print?- /**
- * Do either or both things: (1) change the current configuration, and (2)
- * make sure the given activity is running with the (now) current
- * configuration. Returns true if the activity has been left running, or
- * false if <var>starting</var> is being destroyed to match the new
- * configuration.
- * @param persistent TODO
- */
- boolean updateConfigurationLocked(Configuration values,
- ctivityRecord starting, boolean persistent, boolean initLocale) {
- int changes = 0;
- if (values != null) {
- Configuration newConfig = new Configuration(mConfiguration);
- changes = newConfig.updateFrom(values);
- for (int i=mLruProcesses.size()-1; i>=0; i–) {
- ProcessRecord app = mLruProcesses.get(i);
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, “Sending to proc ”
- + app.processName + ” new config ” + mConfiguration);
- app.thread.scheduleConfigurationChanged(configCopy);
- }
- } catch (Exception e) {
- }
- }
- boolean kept = true;
- final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
- // mainStack is null during startup.
- if (mainStack != null) {
- if (changes != 0 && starting == null) {
- // If the configuration changed, and the caller is not already
- // in the process of starting an activity, then find the top
- // activity to check if its configuration needs to change.
- starting = mainStack.topRunningActivityLocked(null);
- }
- if (starting != null) {
- kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
- }
- }
- if (values != null && mWindowManager != null) {
- mWindowManager.setNewConfiguration(mConfiguration);
- }
- return kept;
- }
/**
* Do either or both things: (1) change the current configuration, and (2)
* make sure the given activity is running with the (now) current
* configuration. Returns true if the activity has been left running, or
* false if <var>starting</var> is being destroyed to match the new
* configuration.
* @param persistent TODO
*/
boolean updateConfigurationLocked(Configuration values,
ctivityRecord starting, boolean persistent, boolean initLocale) {
int changes = 0;
if (values != null) {
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
try {
if (app.thread != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new config " + mConfiguration);
app.thread.scheduleConfigurationChanged(configCopy);
}
} catch (Exception e) {
}
}
boolean kept = true;
final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
// mainStack is null during startup.
if (mainStack != null) {
if (changes != 0 && starting == null) {
// If the configuration changed, and the caller is not already
// in the process of starting an activity, then find the top
// activity to check if its configuration needs to change.
starting = mainStack.topRunningActivityLocked(null);
}
if (starting != null) {
kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
}
}
if (values != null && mWindowManager != null) {
mWindowManager.setNewConfiguration(mConfiguration);
}
return kept;
}
通常當發生橫豎屏切換的時候,Activity的生命週期通常是:onConfigureationChanged –> onDestroy –> onCreate –> onStart –> onResume。一看這裡就分為兩步驟,一:通知Configuration已經改變;二:獲取棧頂的Activity,重新執行該Activity,以適配新的Configuration。
IApplicationThread是一個aidl檔案。這裡最終呼叫的是ApplicationThread物件,而ApplicationThread類是ActivityThread的一個內部類。
ActivityThread.java (android-6.0\frameworks\base\core\java\android\app)
[java] view plain copy print?- publicvoid scheduleConfigurationChanged(Configuration config) {
- updatePendingConfiguration(config);
- sendMessage(H.CONFIGURATION_CHANGED, config);
- }
public void scheduleConfigurationChanged(Configuration config) {
updatePendingConfiguration(config);
sendMessage(H.CONFIGURATION_CHANGED, config);
}
直接通過Handler機制與ActivityThread進行通訊。
[java] view plain copy print?- publicvoid handleMessage(Message msg) {
- case CONFIGURATION_CHANGED:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ”configChanged”);
- mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
- handleConfigurationChanged((Configuration)msg.obj, null);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
- }
- if (DEBUG_MESSAGES) Slog.v(TAG, “<<< done: ” + codeToString(msg.what));
- }
public void handleMessage(Message msg) {
case CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
handleConfigurationChanged((Configuration)msg.obj, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
[java] view plain copy print?- finalvoid handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
- ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
- freeTextLayoutCachesIfNeeded(configDiff);
- if (callbacks != null) {
- finalint N = callbacks.size();
- for (int i=0; i<N; i++) {
- performConfigurationChanged(callbacks.get(i), config);
- }
- }
- }
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
freeTextLayoutCachesIfNeeded(configDiff);
if (callbacks != null) {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
performConfigurationChanged(callbacks.get(i), config);
}
}
}
[java] view plain copy print?
- privatestaticvoid performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {
- // Only for Activity objects, check that they actually call up to their
- // superclass implementation. ComponentCallbacks2 is an interface, so
- // we check the runtime type and act accordingly.
- Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
- if (shouldChangeConfig) {
- cb.onConfigurationChanged(config);
- }
private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {
// Only for Activity objects, check that they actually call up to their
// superclass implementation. ComponentCallbacks2 is an interface, so
// we check the runtime type and act accordingly.
Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
if (shouldChangeConfig) {
cb.onConfigurationChanged(config);
}
很明顯,在這裡呼叫了onConfigurationChanged方法。也就是常說在橫豎屏切換的時候先呼叫Activity的onConfigurationChanged,通常會重寫這個方法,做一些儲存引數之類的操作。
在呼叫完onConfigurationChanged後,Activity會重新建立。所以就回到AMS的updateConfigurationLocked方法中。
kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
mainStack:ActivityStack。
ActivityStack.java (android-6.0\frameworks\base\services\core\java\com\android\server\am)
[java] view plain copy print?- /**
- * Make sure the given activity matches the current configuration. Returns
- * false if the activity had to be destroyed. Returns true if the
- * configuration is the same, or the activity will remain running as-is
- * for whatever reason. Ensures the HistoryRecord is updated with the
- * correct configuration and all other bookkeeping is handled.
- */
- finalboolean ensureActivityConfigurationLocked(ActivityRecord r,
- int globalChanges) {
- 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_CONFIGURATION,
- ”Config is destroying non-running ” + r);
- destroyActivityLocked(r, true, “config”);
- } elseif (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_CONFIGURATION,
- ”Config is skipping already pausing ” + r);
- r.configDestroy = true;
- returntrue;
- } elseif (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing
- // 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_CONFIGURATION,
- ”Config is relaunching resumed ” + r);
- relaunchActivityLocked(r, r.configChangeFlags, true);
- r.configChangeFlags = 0;
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- ”Config is relaunching non-resumed ” + r);
- relaunchActivityLocked(r, r.configChangeFlags, false);
- r.configChangeFlags = 0;
- }
- // All done… tell the caller we weren’t able to keep this
- // activity around.
- returnfalse;
- }
- returntrue;
- }
/**
* Make sure the given activity matches the current configuration. Returns
* false if the activity had to be destroyed. Returns true if the
* configuration is the same, or the activity will remain running as-is
* for whatever reason. Ensures the HistoryRecord is updated with the
* correct configuration and all other bookkeeping is handled.
*/
final boolean ensureActivityConfigurationLocked(ActivityRecord r,
int globalChanges) {
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_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_CONFIGURATION,
"Config is skipping already pausing " + r);
r.configDestroy = true;
return true;
} else if (r.state == ActivityState.RESUMED) {
// Try to optimize this case: the configuration is changing
// 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_CONFIGURATION,
"Config is relaunching resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, true);
r.configChangeFlags = 0;
} else {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Config is relaunching non-resumed " + r);
relaunchActivityLocked(r, r.configChangeFlags, false);
r.configChangeFlags = 0;
}
// All done... tell the caller we weren't able to keep this
// activity around.
return false;
}
return true;
}
[java] view plain copy print?- privateboolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {
- try {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
- ”Moving to ” + (andResume ? “RESUMED” : “PAUSED”) + “ Relaunching ” + r);
- r.forceNewConfig = false;
- r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
- !andResume, new Configuration(mService.mConfiguration),
- new Configuration(mOverrideConfig));
- // Note: don’t need to call pauseIfSleepingLocked() here, because
- // the caller will only pass in ‘andResume’ if this activity is
- // currently resumed, which implies we aren’t sleeping.
- } catch (RemoteException e) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, “Relaunch failed”, e);
- }
- returntrue;
- }
private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {
try {
if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
"Moving to " + (andResume ? "RESUMED" : "PAUSED") + "