Android 屏幕旋转事件流程分析

本文转自:https://blog.csdn.net/wo_sxn/article/details/52345323

WindowManagerService.java (android-6.0\frameworks\base\services\core\java\com\android\server\wm)
  1. private void initPolicy() {  
  2.     UiThread.getHandler().runWithScissors(new Runnable() {  
  3.         @Override  
  4.         public void run() {  
  5.             WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());  
  6.   
  7.             mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);  
  8.         }  
  9.     }, 0);  
  10. }  
    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);
    }
在WMS构造方法中就调用initPolicy方法。在这个方法中,很明显是在初始化mPolicy:WindowManagerPolicy这个变量。
在WMS中,该变量实质是PhoneWindowManager对象。PhoneWindowManager类实现了WindowManagerPolicy接口类。

PhoneWindowManager.java (android-6.0\frameworks\base\services\core\java\com\android\server\policy)
  1. /** {@inheritDoc} */  
  2.  @Override  
  3.  public void init(Context context, IWindowManager windowManager,  
  4.          WindowManagerFuncs windowManagerFuncs) {  
  5.      mContext = context;  
  6.      mWindowManager = windowManager;  
  7.      mWindowManagerFuncs = windowManagerFuncs;  
  8.   
  9.      mOrientationListener = new MyOrientationListener(mContext, mHandler);  
  10.      try {  
  11.          mOrientationListener.setCurrentRotation(windowManager.getRotation());  
  12.      } catch (RemoteException ex) { }  
  13.   
  14.  }  
   /** {@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)
  1. private WindowOrientationListener(Context context, Handler handler, int rate) {  
  2.     mHandler = handler;  
  3.     mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);  
  4.     mRate = rate;  
  5.     mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR  
  6.             ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);  
  7.     if (mSensor != null) {  
  8.         // Create listener only if sensors do exist  
  9.         mSensorEventListener = new SensorEventListenerImpl(context);  
  10.     }  
  11. }  
    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。

  1.  * Enables the WindowOrientationListener so it will monitor the sensor and call  
  2.  * {@link #onProposedRotationChanged(int)} when the device orientation changes.  
  3.  */  
  4. public void enable() {  
  5.   
  6.             mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);  
  7.             mEnabled = true;  
  8.         }  
  9.     }  
  10. }  
     * 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
  1. public void onSensorChanged(SensorEvent event) {  
  2.     int proposedRotation;  
  3.     int oldProposedRotation;  
  4.   
  5.     synchronized (mLock) {  
  6.         // The vector given in the SensorEvent points straight up (towards the sky) under  
  7.         // ideal conditions (the phone is not accelerating).  I’ll call this up vector  
  8.         // elsewhere.  
  9.         float x = event.values[ACCELEROMETER_DATA_X];  
  10.         float y = event.values[ACCELEROMETER_DATA_Y];  
  11.         float z = event.values[ACCELEROMETER_DATA_Z];  
  12.         }  
  13.     }  
  14.   
  15.     // Tell the listener.  
  16.     if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {  
  17.         if (LOG) {  
  18.             Slog.v(TAG, ”Proposed rotation changed!  proposedRotation=” + proposedRotation  
  19.                     + ”, oldProposedRotation=” + oldProposedRotation);  
  20.         }  
  21.         onProposedRotationChanged(proposedRotation);  
  22.     }  
  23. }  
        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方法的最后通过函数回调上报旋屏事件。回顾上面的内容,验证的确如此。

  1. /** 
  2.  * Called when the rotation view of the device has changed. 
  3.  * 
  4.  * This method is called whenever the orientation becomes certain of an orientation. 
  5.  * It is called each time the orientation determination transitions from being 
  6.  * uncertain to being certain again, even if it is the same orientation as before. 
  7.  * 
  8.  * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants. 
  9.  * @see android.view.Surface 
  10.  */  
  11. public abstract void 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)
  1. @Override  
  2. public void onProposedRotationChanged(int rotation) {  
  3.     if (localLOGV) Slog.v(TAG, “onProposedRotationChanged, rotation=” + rotation);  
  4.     updateRotation(false);  
  5. }  
        @Override
        public void onProposedRotationChanged(int rotation) {
            if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
            updateRotation(false);
        }

  1. void updateRotation(boolean alwaysSendConfiguration) {  
  2.     try {  
  3.         //set orientation on WindowManager  
  4.         mWindowManager.updateRotation(alwaysSendConfiguration, false); //false、false  
  5.     } catch (RemoteException e) {  
  6.         // Ignore  
  7.     }  
  8. }  
    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)
  1. /** 
  2.  * Recalculate the current rotation. 
  3.  * 
  4.  * Called by the window manager policy whenever the state of the system changes 
  5.  * such that the current rotation might need to be updated, such as when the 
  6.  * device is docked or rotated into a new posture. 
  7.  */  
  8. @Override  
  9. public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  10.     updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);  
  11. }  
    /**
     * 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);
    }

  1. public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {  
  2.   
  3.     boolean changed;  
  4.     synchronized(mWindowMap) {  
  5.         changed = updateRotationUncheckedLocked(false);  
  6.   
  7.     if (changed || alwaysSendConfiguration) {  
  8.         sendNewConfiguration();  
  9.     }  
  10.   
  11. }  
    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {

        boolean changed;
        synchronized(mWindowMap) {
            changed = updateRotationUncheckedLocked(false);

        if (changed || alwaysSendConfiguration) {
            sendNewConfiguration();
        }

    }
一般情况,rotation都是发生变化的,也就是说 updateRotationUncheckedLocked返回值通常为true,故会调用sendNewConfiguration。

  1. /* 
  2.  * Instruct the Activity Manager to fetch the current configuration and broadcast 
  3.  * that to config-changed listeners if appropriate. 
  4.  */  
  5. void sendNewConfiguration() {  
  6.     try {  
  7.         mActivityManager.updateConfiguration(null);  
  8.     } catch (RemoteException e) {  
  9.     }  
  10. }  
    /*
     * 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)
  1. public void updateConfiguration(Configuration values) {  
  2.     enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,  
  3.             ”updateConfiguration()”);  
  4.   
  5.     synchronized(this) {  
  6.         if (values == null && mWindowManager != null) {  
  7.             // sentinel: fetch the current configuration from the window manager  
  8.             values = mWindowManager.computeNewConfiguration();  
  9.         }  
  10.   
  11.         updateConfigurationLocked(values, nullfalsefalse);  
  12.   
  13.     }  
  14. }  
    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值。

  1. /** 
  2.  * Do either or both things: (1) change the current configuration, and (2) 
  3.  * make sure the given activity is running with the (now) current 
  4.  * configuration.  Returns true if the activity has been left running, or 
  5.  * false if <var>starting</var> is being destroyed to match the new 
  6.  * configuration. 
  7.  * @param persistent TODO 
  8.  */  
  9. boolean updateConfigurationLocked(Configuration values,  
  10.         ctivityRecord starting, boolean persistent, boolean initLocale) {  
  11.     int changes = 0;  
  12.   
  13.     if (values != null) {  
  14.         Configuration newConfig = new Configuration(mConfiguration);  
  15.         changes = newConfig.updateFrom(values);  
  16.   
  17.             for (int i=mLruProcesses.size()-1; i>=0; i–) {  
  18.                 ProcessRecord app = mLruProcesses.get(i);  
  19.                 try {  
  20.                     if (app.thread != null) {  
  21.                         if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, “Sending to proc ”  
  22.                                 + app.processName + ” new config ” + mConfiguration);  
  23.                         app.thread.scheduleConfigurationChanged(configCopy);  
  24.                     }  
  25.                 } catch (Exception e) {  
  26.                 }  
  27.             }  
  28.   
  29.     boolean kept = true;  
  30.     final ActivityStack mainStack = mStackSupervisor.getFocusedStack();  
  31.     // mainStack is null during startup.  
  32.     if (mainStack != null) {  
  33.         if (changes != 0 && starting == null) {  
  34.             // If the configuration changed, and the caller is not already  
  35.             // in the process of starting an activity, then find the top  
  36.             // activity to check if its configuration needs to change.  
  37.             starting = mainStack.topRunningActivityLocked(null);  
  38.         }  
  39.   
  40.         if (starting != null) {  
  41.             kept = mainStack.ensureActivityConfigurationLocked(starting, changes);  
  42.             // And we need to make sure at this point that all other activities  
  43.             // are made visible with the correct configuration.  
  44.             mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);  
  45.         }  
  46.     }  
  47.   
  48.     if (values != null && mWindowManager != null) {  
  49.         mWindowManager.setNewConfiguration(mConfiguration);  
  50.     }  
  51.   
  52.     return kept;  
  53. }  
    /**
     * 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)
  1. public void scheduleConfigurationChanged(Configuration config) {  
  2.     updatePendingConfiguration(config);  
  3.     sendMessage(H.CONFIGURATION_CHANGED, config);  
  4. }  
        public void scheduleConfigurationChanged(Configuration config) {
            updatePendingConfiguration(config);
            sendMessage(H.CONFIGURATION_CHANGED, config);
        }
直接通过Handler机制与ActivityThread进行通信。

  1. public void handleMessage(Message msg) {  
  2.   
  3.         case CONFIGURATION_CHANGED:  
  4.             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ”configChanged”);  
  5.             mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;  
  6.             handleConfigurationChanged((Configuration)msg.obj, null);  
  7.             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
  8.             break;  
  9.     }  
  10.     if (DEBUG_MESSAGES) Slog.v(TAG, “<<< done: ” + codeToString(msg.what));  
  11. }  
        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));
        }

  1. final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {  
  2.   
  3.     ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);  
  4.   
  5.     freeTextLayoutCachesIfNeeded(configDiff);  
  6.   
  7.     if (callbacks != null) {  
  8.         final int N = callbacks.size();  
  9.         for (int i=0; i<N; i++) {  
  10.             performConfigurationChanged(callbacks.get(i), config);  
  11.         }  
  12.     }  
  13. }  
    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);
            }
        }
    }

  1. private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {  
  2.     // Only for Activity objects, check that they actually call up to their  
  3.     // superclass implementation.  ComponentCallbacks2 is an interface, so  
  4.     // we check the runtime type and act accordingly.  
  5.     Activity activity = (cb instanceof Activity) ? (Activity) cb : null;  
  6.   
  7.     if (shouldChangeConfig) {  
  8.         cb.onConfigurationChanged(config);  
  9.   
  10. }  
    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)
  1. /** 
  2.  * Make sure the given activity matches the current configuration.  Returns 
  3.  * false if the activity had to be destroyed.  Returns true if the 
  4.  * configuration is the same, or the activity will remain running as-is 
  5.  * for whatever reason.  Ensures the HistoryRecord is updated with the 
  6.  * correct configuration and all other bookkeeping is handled. 
  7.  */  
  8. final boolean ensureActivityConfigurationLocked(ActivityRecord r,  
  9.         int globalChanges) {  
  10.   
  11.     if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {  
  12.         // Aha, the activity isn’t handling the change, so DIE DIE DIE.  
  13.         r.configChangeFlags |= changes;  
  14.         r.startFreezingScreenLocked(r.app, globalChanges);  
  15.         r.forceNewConfig = false;  
  16.         if (r.app == null || r.app.thread == null) {  
  17.             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,  
  18.                     ”Config is destroying non-running ” + r);  
  19.             destroyActivityLocked(r, true“config”);  
  20.         } else if (r.state == ActivityState.PAUSING) {  
  21.             // A little annoying: we are waiting for this activity to  
  22.             // finish pausing.  Let’s not do anything now, but just  
  23.             // flag that it needs to be restarted when done pausing.  
  24.             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,  
  25.                     ”Config is skipping already pausing ” + r);  
  26.             r.configDestroy = true;  
  27.             return true;  
  28.         } else if (r.state == ActivityState.RESUMED) {  
  29.             // Try to optimize this case: the configuration is changing  
  30.             // and we need to restart the top, resumed activity.  
  31.             // Instead of doing the normal handshaking, just say  
  32.             // “restart!”.  
  33.             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,  
  34.                     ”Config is relaunching resumed ” + r);  
  35.             relaunchActivityLocked(r, r.configChangeFlags, true);  
  36.             r.configChangeFlags = 0;  
  37.         } else {  
  38.             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,  
  39.                     ”Config is relaunching non-resumed ” + r);  
  40.             relaunchActivityLocked(r, r.configChangeFlags, false);  
  41.             r.configChangeFlags = 0;  
  42.         }  
  43.   
  44.         // All done…  tell the caller we weren’t able to keep this  
  45.         // activity around.  
  46.         return false;  
  47.     }  
  48.   
  49.     return true;  
  50. }  
    /**
     * 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;
    }

  1. private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {  
  2.   
  3.     try {  
  4.         if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,  
  5.                 ”Moving to ” + (andResume ? “RESUMED” : “PAUSED”) + “ Relaunching ” + r);  
  6.         r.forceNewConfig = false;  
  7.         r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,  
  8.                 !andResume, new Configuration(mService.mConfiguration),  
  9.                 new Configuration(mOverrideConfig));  
  10.         // Note: don’t need to call pauseIfSleepingLocked() here, because  
  11.         // the caller will only pass in ‘andResume’ if this activity is  
  12.         // currently resumed, which implies we aren’t sleeping.  
  13.     } catch (RemoteException e) {  
  14.         if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, “Relaunch failed”, e);  
  15.     }  
  16.   
  17.     return true;  
  18. }  
    private boolean 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);
        }

        return true;
    }
一眼就看明白,同样是在ApplicationThread内部通过Handler与ActivityThead进行通信,然后真正去执行relaunch操作。


总结:
旋屏事件上报流程:
1、传感器(默认为加速度传感器)计算数据,决定是否上报旋屏事件。
2、上报是通过回调函数实现的,在PhoneWindowManger中实现指定接口。
3、PhoneWindowManger与WMS进行交互,通知其更新rotation。
4、WMS更新rotation后,发现的确发生改变了,去通知AMS处理。
5、AMS获取WMS中rotation数据,然后更新处理。通常流程是通过ApplicationThread与ActivityThread交互。最后调用流程是 onConfigurationChanged –> Activity重新创建。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值