系统服务-SystemUI9.0(2)

7.2.2 通知信息的管理与显示

根据用户是否拉下,通知信息表现为一个位于状态栏的图标,或者下拉的条目。通知信息发出声音,提醒用户。信息可以表示一条事件,新的短信,来电,或持续在后台的工作,下载的文件等
1 通知信息的发送
	
public void notify(int id, Notification notification)
{
    notify(null, id, notification);
}

public void notify(String tag, int id, Notification notification)
{
    notifyAsUser(tag, id, notification, mContext.getUser());
}

public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
    //1 获取NotificationManagerService的Bp端代理
    INotificationManager service = getService();
    //2 获取信息发送者的包名
    String pkg = mContext.getPackageName();
    // Fix the notification as best we can.
    Notification.addFieldsFromContext(mContext, notification);

    if (notification.sound != null) {
        notification.sound = notification.sound.getCanonicalUri();
        if (StrictMode.vmFileUriExposureEnabled()) {
            notification.sound.checkFileUriExposed("Notification.sound");
        }

    }
    fixLegacySmallIcon(notification, pkg);
    if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
        if (notification.getSmallIcon() == null) {
            throw new IllegalArgumentException("Invalid notification (no valid small icon): "
                    + notification);
        }
    }
    if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
    notification.reduceImageSizes(mContext);

    ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
    boolean isLowRam = am.isLowRamDevice();
    final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam,
            mContext);
    try {
        //3 将包名 tag id 提交给NotificationManagerService
        service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                copy, user.getIdentifier());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

2 NotificationManagerService中的通知信息
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
        Notification notification, int userId) throws RemoteException {
    enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
            Binder.getCallingPid(), tag, id, notification, userId);
}


void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
        final int callingPid, final String tag, final int id, final Notification notification,
        int incomingUserId) {
    if (DBG) {
        Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
                + " notification=" + notification);
    }
    //1 首先安全检查
    checkCallerIsSystemOrSameApp(pkg);

    final int userId = ActivityManager.handleIncomingUser(callingPid,
            callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
    final UserHandle user = new UserHandle(userId);

    if (pkg == null || notification == null) {
        throw new IllegalArgumentException("null not allowed: pkg=" + pkg
                + " id=" + id + " notification=" + notification);
    }

    // The system can post notifications for any package, let us resolve that.
    final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);

    // Fix the notification as best we can.
    try {
        final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
        Notification.addFieldsFromContext(ai, notification);

        int canColorize = mPackageManagerClient.checkPermission(
                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
        if (canColorize == PERMISSION_GRANTED) {
            notification.flags |= Notification.FLAG_CAN_COLORIZE;
        } else {
            notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
        }

    } catch (NameNotFoundException e) {
        Slog.e(TAG, "Cannot create a context for sending app", e);
        return;
    }

    mUsageStats.registerEnqueuedByApp(pkg);

    // setup local book-keeping
    String channelId = notification.getChannelId();
    if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
        channelId = (new Notification.TvExtender(notification)).getChannelId();
    }
    final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
            notificationUid, channelId, false /* includeDeleted */);
    if (channel == null) {
        final String noChannelStr = "No Channel found for "
                + "pkg=" + pkg
                + ", channelId=" + channelId
                + ", id=" + id
                + ", tag=" + tag
                + ", opPkg=" + opPkg
                + ", callingUid=" + callingUid
                + ", userId=" + userId
                + ", incomingUserId=" + incomingUserId
                + ", notificationUid=" + notificationUid
                + ", notification=" + notification;
        Log.e(TAG, noChannelStr);
        boolean appNotificationsOff = mRankingHelper.getImportance(pkg, notificationUid)
                == NotificationManager.IMPORTANCE_NONE;

        if (!appNotificationsOff) {
            doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
                    "Failed to post notification on channel \"" + channelId + "\"\n" +
                    "See log for more details");
        }
        return;
    }

    final StatusBarNotification n = new StatusBarNotification(
            pkg, opPkg, id, tag, notificationUid, callingPid, notification,
            user, null, System.currentTimeMillis());
    //3 创建NotificationRecord包装所有与此通知相关的信息
    final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
    r.setIsAppImportanceLocked(mRankingHelper.getIsAppImportanceLocked(pkg, callingUid));

    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
        final boolean fgServiceShown = channel.isFgServiceShown();
        if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
                    || !fgServiceShown)
                && (r.getImportance() == IMPORTANCE_MIN
                        || r.getImportance() == IMPORTANCE_NONE)) {
            // Increase the importance of foreground service notifications unless the user had
            // an opinion otherwise (and the channel hasn't yet shown a fg service).
            if (TextUtils.isEmpty(channelId)
                    || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
                r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
            } else {
                channel.setImportance(IMPORTANCE_LOW);
                if (!fgServiceShown) {
                    channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
                    channel.setFgServiceShown(true);
                }
                mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
                r.updateNotificationChannel(channel);
            }
        } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
                && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
            channel.setFgServiceShown(true);
            r.updateNotificationChannel(channel);
        }
    }

    if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
            r.sbn.getOverrideGroupKey() != null)) {
        return;
    }

    // Whitelist pending intents.
    if (notification.allPendingIntents != null) {
        final int intentCount = notification.allPendingIntents.size();
        if (intentCount > 0) {
            final ActivityManagerInternal am = LocalServices
                    .getService(ActivityManagerInternal.class);
            final long duration = LocalServices.getService(
                    DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
            for (int i = 0; i < intentCount; i++) {
                PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
                if (pendingIntent != null) {
                    am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
                            WHITELIST_TOKEN, duration);
                }
            }
        }
    }

    mHandler.post(new EnqueueNotificationRunnable(userId, r));
}

3 StatusBarManagerService中通知信息
通知信息由NotificationManagerService封装为StatusBarNotification并通过StatusBarManagerService.addNotification() 传递给StatusBarManagerService


4 状态栏中的通知信息

7.2.3 系统状态图标区的管理与显示
StatusBarManagerService维护了一个准许显示在系统状态区的预定义的意图列表,这个列表由fameworks/base/core/res/res/values/config.xml中的字符串数组config_statusBarIcons定义。StatusBarManagerService会拒绝使用者提交上述预定义之外的图标。

1 在系统状态图标区显示图标的方法
在系统状态区中显示一个图标使用StatusBarManager.setIcon()

public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) {
    try {
        final IStatusBarService svc = getService();
        if (svc != null) {
            svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,
                contentDescription);
        }
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

2 StatusBarManagerService对系统状态图标的管理
@Override
public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
        String contentDescription) {
    //1 首先是安全性检查 设置者必须有android.permission.STATUS_BAR才能设置系统状态图标
    enforceStatusBar();

    synchronized (mIcons) {
        //3 创建一个StatusBarIcon,用于封装与图标相关的信息
        StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId,
                iconLevel, 0, contentDescription);
        //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
        //4 将新的StatusBarIcon 保存到mIcons中
        mIcons.put(slot, icon);

        if (mBar != null) {
            try {
                //5 将新的StatusBarIcon提交给SystemUI中的状态栏
                mBar.setIcon(slot, icon);
            } catch (RemoteException ex) {
            }
        }
    }
}

mIcons是StatusBarIconList类的实例,用于保存系统图标的列表。

config_statusBarIcons 保存系统图标列表


public StatusBarIconControllerImpl(Context context) {
    super(context.getResources().getStringArray(
            com.android.internal.R.array.config_statusBarIcons));
    Dependency.get(ConfigurationController.class).addCallback(this);

    mContext = context;

    loadDimens();

    SysUiServiceProvider.getComponent(context, CommandQueue.class)
            .addCallbacks(this);
    Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
}
继承
public StatusBarIconList(String[] slots) {
    final int N = slots.length;
    for (int i=0; i < N; i++) {
        mSlots.add(new Slot(slots[i], null));
    }
}

3 在状态栏的系统图标区显示图标
SystemUI的CommandQueue. CommandQueue中与StatusBarManagerService一样保存了一个StatusBarIconList的实例mList。CommandQueue会检查给定的意图在mList中是否存在一个StatusBarIcon。不存在时会通过调用StatusBar.addIcon()添加一个图标


4 系统状态图标的主要设置者 PhoneStatusBarPolicy
在StatusBar.start()中被创建
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
PhoneStatusBarPolicy工作原理与NetworkController/BatteryController组件一样,通过监听系统状态相关的广播,在广播来时调用StatusBarManager.setIcon()修改系统状态图标

filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
根据接收的广播调用对应方法
updateTTY();
updateBluetooth();

扩充预定义的图标列表
frameworks/base/core/res/res/values/config.xml config_statusBarIcons

锁屏
时序图
在这里插入图片描述

https://blog.youkuaiyun.com/f2006116/article/details/82459134

按下电源键、屏幕显示时间超时、解锁(滑动 图案 指纹 声音 人脸 虹膜)、屏下显示通知管理者

启动锁屏
public class KeyguardViewMediator extends SystemUI {}

@Override
public void start() {
    synchronized (this) {
        setupLocked();
    }
    putComponent(KeyguardViewMediator.class, this);
}

private void setupLocked() {
    mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
    // 创建PARTIAL_WAKE_LOCK
    mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
    // 设置WakeLock为不计数机制
    mShowKeyguardWakeLock.setReferenceCounted(false);

    IntentFilter filter = new IntentFilter();
    // 关机广播
    filter.addAction(Intent.ACTION_SHUTDOWN);
    mContext.registerReceiver(mBroadcastReceiver, filter);

    final IntentFilter delayedActionFilter = new IntentFilter();
    delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
    delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
    mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
            SYSTEMUI_PERMISSION, null /* scheduler */);

    mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);

    mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

    mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);

    mLockPatternUtils = new LockPatternUtils(mContext);
    KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());

    // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
    // is disabled.
    if (mContext.getResources().getBoolean(
            com.android.keyguard.R.bool.config_enableKeyguardService)) {
        setShowingLocked(!shouldWaitForProvisioning()
                && !mLockPatternUtils.isLockScreenDisabled(
                        KeyguardUpdateMonitor.getCurrentUser()),
                mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */);
    } else {
        // The system's keyguard is disabled or missing.
        setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true);
    }
    //statusbar 和keyguard关联
    mStatusBarKeyguardViewManager =
            SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
                    mViewMediatorCallback, mLockPatternUtils);
    final ContentResolver cr = mContext.getContentResolver();
    //获取设备可交互状态
    mDeviceInteractive = mPM.isInteractive();
    //加载锁屏解锁音频和音量
    mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
    String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
    if (soundPath != null) {
        mLockSoundId = mLockSounds.load(soundPath, 1);
    }
    if (soundPath == null || mLockSoundId == 0) {
        Log.w(TAG, "failed to load lock sound from " + soundPath);
    }
    soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
    if (soundPath != null) {
        mUnlockSoundId = mLockSounds.load(soundPath, 1);
    }
    if (soundPath == null || mUnlockSoundId == 0) {
        Log.w(TAG, "failed to load unlock sound from " + soundPath);
    }
    soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);
    if (soundPath != null) {
        mTrustedSoundId = mLockSounds.load(soundPath, 1);
    }
    if (soundPath == null || mTrustedSoundId == 0) {
        Log.w(TAG, "failed to load trusted sound from " + soundPath);
    }

    int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
            com.android.internal.R.integer.config_lockSoundVolumeDb);
    mLockSoundVolume = (float)Math.pow(10, (float)lockSoundDefaultAttenuation/20);
    //加载动画
    mHideAnimation = AnimationUtils.loadAnimation(mContext,
            com.android.internal.R.anim.lock_screen_behind_enter);

    mWorkLockController = new WorkLockActivityController(mContext);
}

android developer文档关于WakeLock的解释
WakeLock计数机制(setReferenceCounted):
在创建了PowerManager.WakeLock 后,有两种机制,第一种是不计数锁机制,另一种是计数锁机制。这可以通过setReferenceCounted( boolean value) 来指定,默认为计数机制。这两种机制的区别在于,前者无论acquire() 了多少次,只要通过一次release() 即可解锁。而后者正真解锁是在(--count == 0 )的时候,同样当(count == 0) 的时候才会去申请加锁,其他情况下isHeld 状态是不会改变的。所以PowerManager.WakeLock 的计数机制并不是正真意义上的对每次请求进行申请/释放每一把锁,它只是对同一把锁被申请/释放的次数进行了统计。


KeyguardService的启动

public class KeyguardService extends Service {}

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@Override
public void systemBooted() {
    bindKeyguard();
    synchronized (mLock) {
        mSystemBooted = true;
        if (mSystemReady) {
            mKeyguardDelegate.onBootCompleted();
        }
    }
    startedWakingUp();
    screenTurningOn(null);
    screenTurnedOn();
}

private void bindKeyguard() {
    synchronized (mLock) {
        if (mKeyguardBound) {
            return;
        }
        mKeyguardBound = true;
    }
    mKeyguardDelegate.bindService(mContext);
}

frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

public void bindService(Context context) {
    Intent intent = new Intent();
    final Resources resources = context.getApplicationContext().getResources();

    final ComponentName keyguardComponent = ComponentName.unflattenFromString(
            resources.getString(com.android.internal.R.string.config_keyguardComponent));
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    intent.setComponent(keyguardComponent);

    if (!context.bindServiceAsUser(intent, mKeyguardConnection,
            Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
        Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
        mKeyguardState.showing = false;
        mKeyguardState.showingAndNotOccluded = false;
        mKeyguardState.secure = false;
        synchronized (mKeyguardState) {
            // TODO: Fix synchronisation model in this class. The other state in this class
            // is at least self-healing but a race condition here can lead to the scrim being
            // stuck on keyguard-less devices.
            mKeyguardState.deviceHasKeyguard = false;
        }
    } else {
        if (DEBUG) Log.v(TAG, "*** Keyguard started");
    }
}

private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
        //KeyguardServiceWrapper 为KeyguardService的包装类
        mKeyguardService = new KeyguardServiceWrapper(mContext,
                IKeyguardService.Stub.asInterface(service), mCallback);
        if (mKeyguardState.systemIsReady) {
            // If the system is ready, it means keyguard crashed and restarted.
            mKeyguardService.onSystemReady();
            if (mKeyguardState.currentUser != UserHandle.USER_NULL) {
                // There has been a user switch earlier
                mKeyguardService.setCurrentUser(mKeyguardState.currentUser);
            }
            // This is used to hide the scrim once keyguard displays.
            if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE
                    || mKeyguardState.interactiveState == INTERACTIVE_STATE_WAKING) {
                mKeyguardService.onStartedWakingUp();
            }
            if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
                mKeyguardService.onFinishedWakingUp();
            }
            if (mKeyguardState.screenState == SCREEN_STATE_ON
                    || mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {
                mKeyguardService.onScreenTurningOn(
                        new KeyguardShowDelegate(mDrawnListenerWhenConnect));
            }
            if (mKeyguardState.screenState == SCREEN_STATE_ON) {
                mKeyguardService.onScreenTurnedOn();
            }
            mDrawnListenerWhenConnect = null;
        }
        if (mKeyguardState.bootCompleted) {
            mKeyguardService.onBootCompleted();
        }
        if (mKeyguardState.occluded) {
            mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
        }
        if (!mKeyguardState.enabled) {
            mKeyguardService.setKeyguardEnabled(mKeyguardState.enabled);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
        mKeyguardService = null;
        mKeyguardState.reset();
        mHandler.post(() -> {
            try {
                // There are no longer any keyguard windows on secondary displays, so pass
                // INVALID_DISPLAY. All that means is that showWhenLocked activities on
                // secondary displays now get to show.
                ActivityManager.getService().setLockScreenShown(true /* keyguardShowing */,
                        false /* aodShowing */, INVALID_DISPLAY);
            } catch (RemoteException e) {
                // Local call.
            }
        });
    }
};

绑定后,PhoneWindowManager可以调用代理类KeyguardServiceDelegate调用KeyguardService的方法进行锁屏相关状态回调
开机keyguard 显示锁流程:

系统启动完成后,PhoneWindowManager.systemReady()

@Override
public void systemReady() {
    // In normal flow, systemReady is called before other system services are ready.
    // So it is better not to bind keyguard here.
    mKeyguardDelegate.onSystemReady();

    mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
    if (mVrManagerInternal != null) {
        mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
    }

    readCameraLensCoverState();
    updateUiMode();
    synchronized (mLock) {
        updateOrientationListenerLp();
        mSystemReady = true;
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                updateSettings();
            }
        });
        // If this happens, for whatever reason, systemReady came later than systemBooted.
        // And keyguard should be already bound from systemBooted
        if (mSystemBooted) {
            mKeyguardDelegate.onBootCompleted();
        }
    }

    mSystemGestures.systemReady();
    mImmersiveModeConfirmation.systemReady();

    mAutofillManagerInternal = LocalServices.getService(AutofillManagerInternal.class);
}

 mKeyguardDelegate.onSystemReady();
public void onSystemReady() {
    if (mKeyguardService != null) {
        mKeyguardService.onSystemReady();
    } else {
        mKeyguardState.systemIsReady = true;
    }
}

KeyguardServiceWrapper.java
@Override // Binder interface
public void onSystemReady() {
    try {
        mService.onSystemReady();
    } catch (RemoteException e) {
        Slog.w(TAG , "Remote Exception", e);
    }
}

KeyguardServic.java
@Override // Binder interface
public void onSystemReady() {
    Trace.beginSection("KeyguardService.mBinder#onSystemReady");
    checkPermission();
    mKeyguardViewMediator.onSystemReady();
    Trace.endSection();
}

KeyguardViewMediator.java
public void onSystemReady() {
    mHandler.obtainMessage(SYSTEM_READY).sendToTarget();
}

case SYSTEM_READY:
    handleSystemReady();
    break;

private void handleSystemReady() {
    synchronized (this) {
        if (DEBUG) Log.d(TAG, "onSystemReady");
        mSystemReady = true;
        doKeyguardLocked(null);
        mUpdateMonitor.registerCallback(mUpdateCallback);
    }
    // Most services aren't available until the system reaches the ready state, so we
    // send it here when the device first boots.
    maybeSendUserPresentBroadcast();
}

private void doKeyguardLocked(Bundle options) {
    //判断是否为安全启动
    if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
        // Don't show keyguard during half-booted cryptkeeper stage.
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
        return;
    }
...
showLocked(options);
}

private void showLocked(Bundle options) {
    Trace.beginSection("KeyguardViewMediator#showLocked aqcuiring mShowKeyguardWakeLock");
    if (DEBUG) Log.d(TAG, "showLocked");
    // ensure we stay awake until we are finished displaying the keyguard
    mShowKeyguardWakeLock.acquire();
    Message msg = mHandler.obtainMessage(SHOW, options);
    mHandler.sendMessage(msg);
    Trace.endSection();
}

case SHOW:
    handleShow((Bundle) msg.obj);
    break;

private void handleShow(Bundle options) {
    Trace.beginSection("KeyguardViewMediator#handleShow");
    final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
    if (mLockPatternUtils.isSecure(currentUser)) {
        mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
    }
    synchronized (KeyguardViewMediator.this) {
        if (!mSystemReady) {
            if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
            return;
        } else {
            if (DEBUG) Log.d(TAG, "handleShow");
        }

        setShowingLocked(true, mAodShowing);
        //显示keyguard
        mStatusBarKeyguardViewManager.show(options);
        mHiding = false;
        mWakeAndUnlocking = false;
        resetKeyguardDonePendingLocked();
        mHideAnimationRun = false;
        adjustStatusBarLocked();
        userActivity();
        mShowKeyguardWakeLock.release();
    }
    mKeyguardDisplayManager.show();
    Trace.endSection();
}

接着处理keyguard绘制逻辑,主要在StatusBarKeyguardViewManager中调用showBouncerOrKeyguard()去显示notification keyguard还是bouncer,在灭屏情况下,再次亮屏看到一般是notification keyguard,就是有消息通知、时间之类的view,上滑会显示密码解锁界面bouncer,接着会调用showkeyguard(),由于还未绘制内容,会进行keyguard的绘制

StatusBarKeyguardViewManager.java
public void show(Bundle options) {
    mShowing = true;
    mStatusBarWindowManager.setKeyguardShowing(true);
    reset(true /* hideBouncerWhenShowing */);
    StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED,
        StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
}

public void reset(boolean hideBouncerWhenShowing) {
    if (mShowing) {
        if (mOccluded && !mDozing) {
            mStatusBar.hideKeyguard();
            if (hideBouncerWhenShowing || mBouncer.needsFullscreenBouncer()) {
                hideBouncer(false /* destroyView */);
            }
        } else {
            showBouncerOrKeyguard(hideBouncerWhenShowing);
        }
        KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
        updateStates();
    }
}

protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
    if (mBouncer.needsFullscreenBouncer() && !mDozing) {
        // The keyguard might be showing (already). So we need to hide it.
        mStatusBar.hideKeyguard();
        mBouncer.show(true /* resetSecuritySelection */);
    } else {
        mStatusBar.showKeyguard();
        if (hideBouncerWhenShowing) {
            hideBouncer(shouldDestroyViewOnReset() /* destroyView */);
            mBouncer.prepare();
        }
    }
    updateStates();
}

public void prepare() {
    boolean wasInitialized = mRoot != null;
    ensureView();
    if (wasInitialized) {
        mKeyguardView.showPrimarySecurityScreen();
    }
    mBouncerPromptReason = mCallback.getBouncerPromptReason();
}

public void showPrimarySecurityScreen() {
    if (DEBUG) Log.d(TAG, "show()");
    mSecurityContainer.showPrimarySecurityScreen(false);
}

void showPrimarySecurityScreen(boolean turningOff) {
    SecurityMode securityMode = mSecurityModel.getSecurityMode(
            KeyguardUpdateMonitor.getCurrentUser());
    if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
    showSecurityScreen(securityMode);
}


按power键,keyguard加载流程
在灭屏时加载,确保亮屏起来时,用户能第一时间看到解锁界面
PhoneWindowManager.java
@Override
public void finishedGoingToSleep(int why) {
    EventLog.writeEvent(70000, 0);
    if (DEBUG_WAKEUP) Slog.i(TAG, "Finished going to sleep... (why=" + why + ")");
    MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);

    mGoingToSleep = false;
    mRequestedOrGoingToSleep = false;

    // We must get this work done here because the power manager will drop
    // the wake lock and let the system suspend once this function returns.
    synchronized (mLock) {
        mAwake = false;
        updateWakeGestureListenerLp();
        updateOrientationListenerLp();
        updateLockScreenTimeout();
    }
    if (mKeyguardDelegate != null) {
        mKeyguardDelegate.onFinishedGoingToSleep(why,
                mCameraGestureTriggeredDuringGoingToSleep);
    }
    mCameraGestureTriggeredDuringGoingToSleep = false;
}

public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
    if (mKeyguardService != null) {
        mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered);
    }
    mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP;
}

@Override
public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
    try {
        mService.onFinishedGoingToSleep(reason, cameraGestureTriggered);
    } catch (RemoteException e) {
        Slog.w(TAG , "Remote Exception", e);
    }
}

@Override // Binder interface
public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) {
    checkPermission();
    mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered);
    mKeyguardLifecyclesDispatcher.dispatch(
            KeyguardLifecyclesDispatcher.FINISHED_GOING_TO_SLEEP);
}

public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) {
    if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + why + ")");
    synchronized (this) {
        mDeviceInteractive = false;
        mGoingToSleep = false;
        mWakeAndUnlocking = false;

        resetKeyguardDonePendingLocked();
        mHideAnimationRun = false;

        notifyFinishedGoingToSleep();

        if (cameraGestureTriggered) {
            Log.i(TAG, "Camera gesture was triggered, preventing Keyguard locking.");

            // Just to make sure, make sure the device is awake.
            mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
                    "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
            mPendingLock = false;
            mPendingReset = false;
        }

        if (mPendingReset) {
            resetStateLocked();
            mPendingReset = false;
        }

        if (mPendingLock) {
            doKeyguardLocked(null);
            mPendingLock = false;
        }

        // We do not have timeout and power button instant lock setting for profile lock.
        // So we use the personal setting if there is any. But if there is no device
        // we need to make sure we lock it immediately when the screen is off.
        if (!mLockLater && !cameraGestureTriggered) {
            doKeyguardForChildProfilesLocked();
        }

    }
    KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
}

private void notifyFinishedGoingToSleep() {
    if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep");
    mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP);
}

case NOTIFY_FINISHED_GOING_TO_SLEEP:
    handleNotifyFinishedGoingToSleep();

private void handleNotifyFinishedGoingToSleep() {
    synchronized (KeyguardViewMediator.this) {
        if (DEBUG) Log.d(TAG, "handleNotifyFinishedGoingToSleep");
        mStatusBarKeyguardViewManager.onFinishedGoingToSleep();
    }
}

public void onFinishedGoingToSleep() {
    mGoingToSleepVisibleNotOccluded = false;
    mBouncer.onScreenTurnedOff();
}


public void onScreenTurnedOff() {
    if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
        mKeyguardView.onPause();
    }
}

public void onPause() {
    if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
            Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
    mSecurityContainer.showPrimarySecurityScreen(true);
    mSecurityContainer.onPause();
    clearFocus();
}

void showPrimarySecurityScreen(boolean turningOff) {
    SecurityMode securityMode = mSecurityModel.getSecurityMode(
            KeyguardUpdateMonitor.getCurrentUser());
    if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
    showSecurityScreen(securityMode);
}

private void showSecurityScreen(SecurityMode securityMode) {
    if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");

    if (securityMode == mCurrentSecuritySelection) return;

    KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
    KeyguardSecurityView newView = getSecurityView(securityMode);

    // Emulate Activity life cycle
    if (oldView != null) {
        oldView.onPause();
        oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
    }
    if (securityMode != SecurityMode.None) {
        newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
        newView.setKeyguardCallback(mCallback);
    }

    // Find and show this child.
    final int childCount = mSecurityViewFlipper.getChildCount();

    final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
    for (int i = 0; i < childCount; i++) {
        if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
            mSecurityViewFlipper.setDisplayedChild(i);
            break;
        }
    }

    mCurrentSecuritySelection = securityMode;
    mSecurityCallback.onSecurityModeChanged(securityMode,
            securityMode != SecurityMode.None && newView.needsInput());
}

private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
    final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
    KeyguardSecurityView view = null;
    final int children = mSecurityViewFlipper.getChildCount();
    for (int child = 0; child < children; child++) {
        if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
            view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
            break;
        }
    }
    int layoutId = getLayoutIdFor(securityMode);
    if (view == null && layoutId != 0) {
        final LayoutInflater inflater = LayoutInflater.from(mContext);
        if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
        View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
        mSecurityViewFlipper.addView(v);
        updateSecurityView(v);
        view = (KeyguardSecurityView)v;
    }

    return view;
}

doKeyguardLocked(null); 显示锁屏的流程
private void doKeyguardLocked(Bundle options) {
    //判断是否为安全启动
    if (KeyguardUpdateMonitor.CORE_APPS_ONLY) {
        // Don't show keyguard during half-booted cryptkeeper stage.
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because booting to cryptkeeper");
        return;
    }

    // if another app is disabling us, don't show
    if (!mExternallyEnabled) {
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");

        // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes
        // for an occasional ugly flicker in this situation:
        // 1) receive a call with the screen on (no keyguard) or make a call
        // 2) screen times out
        // 3) user hits key to turn screen back on
        // instead, we reenable the keyguard when we know the screen is off and the call
        // ends (see the broadcast receiver below)
        // TODO: clean this up when we have better support at the window manager level
        // for apps that wish to be on top of the keyguard
        return;
    }

    // if the keyguard is already showing, don't bother
    if (mStatusBarKeyguardViewManager.isShowing()) {
        if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
        resetStateLocked();
        return;
    }

    // In split system user mode, we never unlock system user.
    if (!mustNotUnlockCurrentUser()
            || !mUpdateMonitor.isDeviceProvisioned()) {

        // if the setup wizard hasn't run yet, don't show
        final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
        final boolean absent = SubscriptionManager.isValidSubscriptionId(
                mUpdateMonitor.getNextSubIdForState(ABSENT));
        final boolean disabled = SubscriptionManager.isValidSubscriptionId(
                mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
        final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
                || ((absent || disabled) && requireSim);

        if (!lockedOrMissing && shouldWaitForProvisioning()) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
                    + " and the sim is not locked or missing");
            return;
        }

        boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
        if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
                && !lockedOrMissing && !forceShow) {
            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
            return;
        }

        if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
            if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
            // Without this, settings is not enabled until the lock screen first appears
            setShowingLocked(false, mAodShowing);
            hideLocked();
            return;
        }
    }

    if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
    showLocked(options);
}


KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);

public void dispatchFinishedGoingToSleep(int why) {
    synchronized(this) {
        mDeviceInteractive = false;
    }
    mHandler.sendMessage(mHandler.obtainMessage(MSG_FINISHED_GOING_TO_SLEEP, why, 0));
}
case MSG_FINISHED_GOING_TO_SLEEP:
    handleFinishedGoingToSleep(msg.arg1);
    break;


protected void handleFinishedGoingToSleep(int arg1) {
    mGoingToSleep = false;
    final int count = mCallbacks.size();
    for (int i = 0; i < count; i++) {
        KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
        if (cb != null) {
            cb.onFinishedGoingToSleep(arg1);
        }
    }
    updateFingerprintListeningState();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值