必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

systemui包括了系统栏和导航栏,必威:以前我们使

2019-09-19 00:20 来源:未知

得到三星的7寸平板,是3.x系统,在气象栏上多了个截屏开关,得到Galaxy Notes 10.1,该功用更加的不可删除的增加在状态栏,既然如此,大家明天在大家平板上也增多上该开关,达成轻易的短平快截屏功效,并不是按POWEENVISION和VOL-进行。

Android 6.0 SystemUI 锁屏流程深入分析

SystemUI 是怎么运维的

systemui满含了系统栏和导航栏,也正是大家看出的电量、时间栏和重临开关那类的导航栏。systemui也是四个apk,所以大家就能够想她是哪些运行的呢,
android 系统的开发银行确定是首先 systemserver, systemserver会运行android 系统所需的种种劳动,比如activtymanagerservice,当mActivityManagerService的systemReady回调后就能够实行运转systemui的动作。

ActivityManagerService 的systemReady

    public void systemReady(final Runnable goingCallback) {
        synchronized(this) {
            if (mSystemReady) {
                // If we're done calling all the receivers, run the next "boot phase" passed in
                // by the SystemServer
                if (goingCallback != null) {
                    goingCallback.run();
                }
                return;
            }

            mLocalDeviceIdleController
                    = LocalServices.getService(DeviceIdleController.LocalService.class);

            // Make sure we have the current profile info, since it is needed for
            // security checks.
            updateCurrentProfileIdsLocked();

            mRecentTasks.clear();
            mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
            mTaskPersister.startPersisting();

            // Check to see if there are any update receivers to run.
            if (!mDidUpdate) {
                if (mWaitingUpdate) {
                    return;
                }
                final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
                mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
                    public void run() {
                        synchronized (ActivityManagerService.this) {
                            mDidUpdate = true;
                        }
                        showBootMessage(mContext.getText(
                                R.string.android_upgrading_complete),
                                false);
                        writeLastDonePreBootReceivers(doneReceivers);
                       systemReady(goingCallback); //这里调到了调到了 SystemServer 里面设置的回调。启动systemui 
                    }
                }, doneReceivers, UserHandle.USER_OWNER);

                if (mWaitingUpdate) {
                    return;
                }
                mDidUpdate = true;
            }

            mAppOpsService.systemReady();
            mSystemReady = true;
        }

        ArrayList<ProcessRecord> procsToKill = null;
        synchronized(mPidsSelfLocked) {
            for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
                ProcessRecord proc = mPidsSelfLocked.valueAt(i);
                if (!isAllowedWhileBooting(proc.info)){
                    if (procsToKill == null) {
                        procsToKill = new ArrayList<ProcessRecord>();
                    }
                    procsToKill.add(proc);
                }
            }
        }

        synchronized(this) {
            if (procsToKill != null) {
                for (int i=procsToKill.size()-1; i>=0; i--) {
                    ProcessRecord proc = procsToKill.get(i);
                    Slog.i(TAG, "Removing system update proc: " + proc);
                    removeProcessLocked(proc, true, false, "system update done");
                }
            }

            // Now that we have cleaned up any update processes, we
            // are ready to start launching real processes and know that
            // we won't trample on them any more.
            mProcessesReady = true;
        }

        Slog.i(TAG, "System now ready");
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
            SystemClock.uptimeMillis());

        synchronized(this) {
            // Make sure we have no pre-ready processes sitting around.

            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                ResolveInfo ri = mContext.getPackageManager()
                        .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
                                STOCK_PM_FLAGS);
                CharSequence errorMsg = null;
                if (ri != null) {
                    ActivityInfo ai = ri.activityInfo;
                    ApplicationInfo app = ai.applicationInfo;
                    if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                        mTopAction = Intent.ACTION_FACTORY_TEST;
                        mTopData = null;
                        mTopComponent = new ComponentName(app.packageName,
                                ai.name);
                    } else {
                        errorMsg = mContext.getResources().getText(
                                com.android.internal.R.string.factorytest_not_system);
                    }
                } else {
                    errorMsg = mContext.getResources().getText(
                            com.android.internal.R.string.factorytest_no_action);
                }
                if (errorMsg != null) {
                    mTopAction = null;
                    mTopData = null;
                    mTopComponent = null;
                    Message msg = Message.obtain();
                    msg.what = SHOW_FACTORY_ERROR_MSG;
                    msg.getData().putCharSequence("msg", errorMsg);
                    mUiHandler.sendMessage(msg);
                }
            }
        }

        retrieveSettings();
        loadResourcesOnSystemReady();

        synchronized (this) {
            readGrantedUriPermissionsLocked();
        }

        if (goingCallback != null) goingCallback.run();

        mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
                Integer.toString(mCurrentUserId), mCurrentUserId);
        mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
                Integer.toString(mCurrentUserId), mCurrentUserId);
        mSystemServiceManager.startUser(mCurrentUserId);

        synchronized (this) {
            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                try {
                    List apps = AppGlobals.getPackageManager().
                        getPersistentApplications(STOCK_PM_FLAGS);
                    if (apps != null) {
                        int N = apps.size();
                        int i;
                        for (i=0; i<N; i++) {
                            ApplicationInfo info
                                = (ApplicationInfo)apps.get(i);
                            if (info != null &&
                                    !info.packageName.equals("android")) {
                                addAppLocked(info, false, null /* ABI override */);
                            }
                        }
                    }
                } catch (RemoteException ex) {
                    // pm is in same process, this will never happen.
                }
            }

            // Start up initial activity.
            mBooting = true;
            startHomeActivityLocked(mCurrentUserId, "systemReady"); //这里启动launcher 应用,所以 systemui 是在launcher之前启动

            try {
                if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
                    Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"
                            + " data partition or your device will be unstable.");
                    mUiHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget();
                }
            } catch (RemoteException e) {
            }

            if (!Build.isBuildConsistent()) {
                Slog.e(TAG, "Build fingerprint is not consistent, warning user");
                mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
            }

            long ident = Binder.clearCallingIdentity();
            try {
                Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
                broadcastIntentLocked(null, null, intent,
                        null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                        null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
                intent = new Intent(Intent.ACTION_USER_STARTING);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
                broadcastIntentLocked(null, null, intent,
                        null, new IIntentReceiver.Stub() {
                            @Override
                            public void performReceive(Intent intent, int resultCode, String data,
                                    Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                                    throws RemoteException {
                            }
                        }, 0, null, null,
                        new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                        null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
            } catch (Throwable t) {
                Slog.wtf(TAG, "Failed sending first user broadcasts", t);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            mStackSupervisor.resumeTopActivitiesLocked();
            sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
        }
    }

SystemServer 当中

// These are needed to propagate to the runnable below.
        final NetworkManagementService networkManagementF = networkManagement;
        final NetworkStatsService networkStatsF = networkStats;
        final NetworkPolicyManagerService networkPolicyF = networkPolicy;
        final ConnectivityService connectivityF = connectivity;
        final NetworkScoreService networkScoreF = networkScore;
        final WallpaperManagerService wallpaperF = wallpaper;
        final InputMethodManagerService immF = imm;
        final LocationManagerService locationF = location;
        final CountryDetectorService countryDetectorF = countryDetector;
        final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
        final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
        final TextServicesManagerService textServiceManagerServiceF = tsms;
        final StatusBarManagerService statusBarF = statusBar;
        final AssetAtlasService atlasF = atlas;
        final InputManagerService inputManagerF = inputManager;
        final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
        final MediaRouterService mediaRouterF = mediaRouter;
        final AudioService audioServiceF = audioService;
        final MmsServiceBroker mmsServiceF = mmsService;

        // We now tell the activity manager it is okay to run third party
        // code.  It will call back into us once it has gotten to the state
        // where third party code can really run (but before it has actually
        // started launching the initial applications), for us to complete our
        // initialization.
        mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
                Slog.i(TAG, "Making services ready");
                mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_ACTIVITY_MANAGER_READY);

                try {
                    mActivityManagerService.startObservingNativeCrashes();
                } catch (Throwable e) {
                    reportWtf("observing native crashes", e);
                }

                Slog.i(TAG, "WebViewFactory preparation");
                WebViewFactory.prepareWebViewInSystemServer();

                try {
                    startSystemUi(context); //启动SystemUi
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }
                try {
                    if (networkScoreF != null) networkScoreF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Score Service ready", e);
                }
                try {
                    if (networkManagementF != null) networkManagementF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Managment Service ready", e);
                }
                try {
                    if (networkStatsF != null) networkStatsF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Stats Service ready", e);
                }
                try {
                    if (networkPolicyF != null) networkPolicyF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Policy Service ready", e);
                }
                try {
                    if (connectivityF != null) connectivityF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Connectivity Service ready", e);
                }
                try {
                    if (audioServiceF != null) audioServiceF.systemReady();
                } catch (Throwable e) {
                    reportWtf("Notifying AudioService running", e);
                }
                Watchdog.getInstance().start();

                // It is now okay to let the various system services start their
                // third party code...
                mSystemServiceManager.startBootPhase(
                        SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);

                try {
                    if (wallpaperF != null) wallpaperF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying WallpaperService running", e);
                }
                try {
                    if (immF != null) immF.systemRunning(statusBarF);
                } catch (Throwable e) {
                    reportWtf("Notifying InputMethodService running", e);
                }
                try {
                    if (locationF != null) locationF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying Location Service running", e);
                }
                try {
                    if (countryDetectorF != null) countryDetectorF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying CountryDetectorService running", e);
                }
                try {
                    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying NetworkTimeService running", e);
                }
                try {
                    if (commonTimeMgmtServiceF != null) {
                        commonTimeMgmtServiceF.systemRunning();
                    }
                } catch (Throwable e) {
                    reportWtf("Notifying CommonTimeManagementService running", e);
                }
                try {
                    if (textServiceManagerServiceF != null)
                        textServiceManagerServiceF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying TextServicesManagerService running", e);
                }
                try {
                    if (atlasF != null) atlasF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying AssetAtlasService running", e);
                }
                try {
                    // TODO(BT) Pass parameter to input manager
                    if (inputManagerF != null) inputManagerF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying InputManagerService running", e);
                }
                try {
                    if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying TelephonyRegistry running", e);
                }
                try {
                    if (mediaRouterF != null) mediaRouterF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying MediaRouterService running", e);
                }

                try {
                    if (mmsServiceF != null) mmsServiceF.systemRunning();
                } catch (Throwable e) {
                    reportWtf("Notifying MmsService running", e);
                }
            }
        });
    }

//启动了 systemui package里面的SystemUIService
 static final void startSystemUi(Context context) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.OWNER);
    }```

###  systemui 中运行了哪些服务?
直接看看 systemuiservice里面代码

package com.android.systemui;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import java.io.FileDescriptor;
import java.io.PrintWriter;

public class SystemUIService extends Service {

@Override
public void onCreate() {
    super.onCreate();
    ((SystemUIApplication) getApplication()).startServicesIfNeeded(); // 只是做了这件事情
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
    if (args == null || args.length == 0) {
        for (SystemUI ui: services) {
            pw.println("dumping service: " + ui.getClass().getName());
            ui.dump(fd, pw, args);
        }
    } else {
        String svc = args[0];
        for (SystemUI ui: services) {
            String name = ui.getClass().getName();
            if (name.endsWith(svc)) {
                ui.dump(fd, pw, args);
            }
        }
    }
}

}

走到了 SystemUIApplication 里面

private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.tuner.TunerService.class,
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recents.Recents.class,
com.android.systemui.volume.VolumeUI.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
};

public void startServicesIfNeeded() {
if (mServicesStarted) {
return;
}

    if (!mBootCompleted) {
        // check to see if maybe it was already completed long before we began
        // see ActivityManagerService.finishBooting()
        if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
            mBootCompleted = true;
            if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
        }
    }

    Log.v(TAG, "Starting SystemUI services.");
    final int N = SERVICES.length;
    for (int i=0; i<N; i++) {
        Class<?> cl = SERVICES[i];
        if (DEBUG) Log.d(TAG, "loading: " + cl);
        try {
            mServices[i] = (SystemUI)cl.newInstance();
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InstantiationException ex) {
            throw new RuntimeException(ex);
        }
        mServices[i].mContext = this;
        mServices[i].mComponents = mComponents;
        if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
        mServices[i].start();

        if (mBootCompleted) {
            mServices[i].onBootCompleted();
        }
    }
    mServicesStarted = true;
}

以上看以看出分别启动了  com.android.systemui.tuner.TunerService.class,
            com.android.systemui.keyguard.KeyguardViewMediator.class,
            com.android.systemui.recents.Recents.class,
            com.android.systemui.volume.VolumeUI.class,
            com.android.systemui.statusbar.SystemBars.class,
            com.android.systemui.usb.StorageNotification.class,
            com.android.systemui.power.PowerUI.class,
            com.android.systemui.media.RingtonePlayer.class,
这些子服务,它自己启动没有干什么事情。

### systemui的那些ui布局是在哪里被显示出来的 ?
带着这个问题 看看com.android.systemui.statusbar.SystemBars.class 这个的实现,
SystemBars.java 中启动

public void start() {
if (DEBUG) Log.d(TAG, "start");
mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
mServiceMonitor.start(); // will call onNoService if no remote service is found
}

再继续跟进ServiceMonitor.java  的start

public void start() {
// listen for setting changes
ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
false /notifyForDescendents/, mSettingObserver, UserHandle.USER_ALL);

    // listen for package/component changes
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_PACKAGE_ADDED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addDataScheme("package");
    mContext.registerReceiver(mBroadcastReceiver, filter)

    mHandler.sendEmptyMessage(MSG_START_SERVICE);
}

上面注册了一个setting数据库的监听器和package change的广播,然而这个不是我们现在关心的,看到最后 mHandler有发送一个消息出去MSG_START_SERVICE。又启动了一个服务?继续看吧

private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_START_SERVICE:
startService();
break;
case MSG_CONTINUE_START_SERVICE:
continueStartService();
break;
case MSG_STOP_SERVICE:
stopService();
break;
case MSG_PACKAGE_INTENT:
packageIntent((Intent)msg.obj);
break;
case MSG_CHECK_BOUND:
checkBound();
break;
case MSG_SERVICE_DISCONNECTED:
serviceDisconnected((ComponentName)msg.obj);
break;
}
}
};

private void startService() {
mServiceName = getComponentNameFromSetting();
if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
if (mServiceName == null) {
mBound = false; //走到了那一个分支
mCallbacks.onNoService();
} else {
long delay = mCallbacks.onServiceStartAttempt();
mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
}
}

public interface Callbacks {
/** The service does not exist or failed to bind /
void onNoService();
/
* The service is about to start, this is a chance to perform cleanup and
* delay the start if necessary */
long onServiceStartAttempt();
}

可见 Callbacks  这个回调是在实现的地方来执行的,实现了它的地方在SystemBars.java

@Override
public void onNoService() {
if (DEBUG) Log.d(TAG, "onNoService");
//这里起先创建statusbar了
createStatusBarFromConfig(); // fallback to using an in-process implementation
}

@Override
public long onServiceStartAttempt() {
    if (DEBUG) Log.d(TAG, "onServiceStartAttempt mStatusBar="+mStatusBar);
    if (mStatusBar != null) {
        // tear down the in-process version, we'll recreate it again if needed
        mStatusBar.destroy();
        mStatusBar = null;
        return WAIT_FOR_BARS_TO_DIE;
    }
    return 0;
}

// in-process fallback implementation, per the product config
private BaseStatusBar mStatusBar;

private void createStatusBarFromConfig() {
if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
final String clsName = mContext.getString(R.string.config_statusBarComponent);
if (clsName == null || clsName.length() == 0) {
throw andLog("No status bar component configured", null);
}
Class<?> cls = null;
try {
cls = mContext.getClassLoader().loadClass(clsName);
} catch (Throwable t) {
throw andLog("Error loading status bar component: " + clsName, t);
}
try {
mStatusBar = (BaseStatusBar) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
mStatusBar.start();
if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

下面就要正在把view相关的内容添加进来了BaseStatusBar 的start()

public void start() {
    mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
    mDisplay = mWindowManager.getDefaultDisplay();
    mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
            Context.DEVICE_POLICY_SERVICE);

    mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);

    mNotificationData = new NotificationData(this);

    mAccessibilityManager = (AccessibilityManager)
            mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

    mDreamManager = IDreamManager.Stub.asInterface(
            ServiceManager.checkService(DreamService.DREAM_SERVICE));
    mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

    mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
            mSettingsObserver);
    mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
            mSettingsObserver);
    mContext.getContentResolver().registerContentObserver(
            Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
            mSettingsObserver,
            UserHandle.USER_ALL);

    mContext.getContentResolver().registerContentObserver(
            Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
            true,
            mLockscreenSettingsObserver,
            UserHandle.USER_ALL);

    mBarService = IStatusBarService.Stub.asInterface(
            ServiceManager.getService(Context.STATUS_BAR_SERVICE));

    mRecents = getComponent(Recents.class);
    mRecents.setCallback(this);

    final Configuration currentConfig = mContext.getResources().getConfiguration();
    mLocale = currentConfig.locale;
    mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
    mFontScale = currentConfig.fontScale;

    mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);

    mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
            android.R.interpolator.linear_out_slow_in);
    mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
            android.R.interpolator.fast_out_linear_in);

    // Connect in to the status bar manager service
    StatusBarIconList iconList = new StatusBarIconList();
    mCommandQueue = new CommandQueue(this, iconList);

    int[] switches = new int[8];
    ArrayList<IBinder> binders = new ArrayList<IBinder>();
    try {
        mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
    } catch (RemoteException ex) {
        // If the system process isn't there we're doomed anyway.
    }

    createAndAddWindows();//创建view 

    mSettingsObserver.onChange(false); // set up
    disable(switches[0], switches[6], false /* animate */);
    setSystemUiVisibility(switches[1], 0xffffffff);
    topAppWindowChanged(switches[2] != 0);
    // StatusBarManagerService has a back up of IME token and it's restored here.
    setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);

    // Set up the initial icon state
    int N = iconList.size();
    int viewIndex = 0;
    for (int i=0; i<N; i++) {
        StatusBarIcon icon = iconList.getIcon(i);
        if (icon != null) {
            addIcon(iconList.getSlot(i), i, viewIndex, icon);
            viewIndex++;
        }
    }

    // Set up the initial notification state.
    try {
        mNotificationListener.registerAsSystemService(mContext,
                new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
                UserHandle.USER_ALL);
    } catch (RemoteException e) {
        Log.e(TAG, "Unable to register notification listener", e);
    }


    if (DEBUG) {
        Log.d(TAG, String.format(
                "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
               iconList.size(),
               switches[0],
               switches[1],
               switches[2],
               switches[3]
               ));
    }

    mCurrentUserId = ActivityManager.getCurrentUser();
    setHeadsUpUser(mCurrentUserId);

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_USER_SWITCHED);
    filter.addAction(Intent.ACTION_USER_ADDED);
    filter.addAction(Intent.ACTION_USER_PRESENT);
    filter.addAction(BANNER_ACTION_CANCEL);
    filter.addAction(BANNER_ACTION_SETUP);
    mContext.registerReceiver(mBroadcastReceiver, filter);

    IntentFilter allUsersFilter = new IntentFilter();
    allUsersFilter.addAction(
            DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
            null, null);
    updateCurrentProfilesCache();
}

可以从源码中看到     protected abstract void createAndAddWindows(); 是一个抽象方法,所以这个应该是由它的子类来进行实现的,PhoneStatusBar.java 中找到了它的实现。

@Override
public void createAndAddWindows() {
addStatusBarWindow();
}

private void addStatusBarWindow() {
    makeStatusBarView();// 加载view
    mStatusBarWindowManager = new StatusBarWindowManager(mContext);
    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}


// ================================================================================
// Constructing the view
// ================================================================================
protected PhoneStatusBarView makeStatusBarView() {
    final Context context = mContext;

    Resources res = context.getResources();

    updateDisplaySize(); // populates mDisplayMetrics
    updateResources();

    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
            R.layout.super_status_bar, null); // view的布局文件
    mStatusBarWindow.setService(this);
    mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            checkUserAutohide(v, event);
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                if (mExpandedVisible) {
                    animateCollapsePanels();
                }
            }
            return mStatusBarWindow.onTouchEvent(event);
        }
    });

    mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
    mStatusBarView.setBar(this);

    PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
    mStatusBarView.setPanelHolder(holder);

    mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
            R.id.notification_panel);
    mNotificationPanel.setStatusBar(this);

    if (!ActivityManager.isHighEndGfx()) {
        mStatusBarWindow.setBackground(null);
        mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                R.color.notification_panel_solid_background)));
    }

    mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
    mHeadsUpManager.setBar(this);
    mHeadsUpManager.addListener(this);
    mHeadsUpManager.addListener(mNotificationPanel);
    mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
    mNotificationData.setHeadsUpManager(mHeadsUpManager);

    if (MULTIUSER_DEBUG) {
        mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                R.id.header_debug_info);
        mNotificationPanelDebugText.setVisibility(View.VISIBLE);
    }

    try {
        boolean showNav = mWindowManagerService.hasNavigationBar();
        if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
        if (showNav) {
            mNavigationBarView =
                (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);

            mNavigationBarView.setDisabledFlags(mDisabled1);
            mNavigationBarView.setBar(this);
            mNavigationBarView.setOnVerticalChangedListener(
                    new NavigationBarView.OnVerticalChangedListener() {
                @Override
                public void onVerticalChanged(boolean isVertical) {
                    if (mAssistManager != null) {
                        mAssistManager.onConfigurationChanged();
                    }
                    mNotificationPanel.setQsScrimEnabled(!isVertical);
                }
            });
            mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    checkUserAutohide(v, event);
                    return false;
                }});
        }
    } catch (RemoteException ex) {
        // no window manager? good luck with that
    }

    mAssistManager = new AssistManager(this, context);

    // figure out which pixel-format to use for the status bar.
    mPixelFormat = PixelFormat.OPAQUE;

    mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
            R.id.notification_stack_scroller);
    mStackScroller.setLongPressListener(getNotificationLongClicker());
    mStackScroller.setPhoneStatusBar(this);
    mStackScroller.setGroupManager(mGroupManager);
    mStackScroller.setHeadsUpManager(mHeadsUpManager);
    mGroupManager.setOnGroupChangeListener(mStackScroller);

    mKeyguardIconOverflowContainer =
            (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
    mKeyguardIconOverflowContainer.setOnActivatedListener(this);
    mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
    mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);

    SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
                    R.layout.status_bar_notification_speed_bump, mStackScroller, false);
    mStackScroller.setSpeedBumpView(speedBump);
    mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
            R.layout.status_bar_no_notifications, mStackScroller, false);
    mStackScroller.setEmptyShadeView(mEmptyShadeView);
    mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
            R.layout.status_bar_notification_dismiss_all, mStackScroller, false);
    mDismissView.setOnButtonClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
            clearAllNotifications();
        }
    });
    mStackScroller.setDismissView(mDismissView);
    mExpandedContents = mStackScroller;

    mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
    mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
    mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);

    ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
    ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
    View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
    mScrimController = new ScrimController(scrimBehind, scrimInFront, headsUpScrim,
            mScrimSrcModeEnabled);
    mHeadsUpManager.addListener(mScrimController);
    mStackScroller.setScrimController(mScrimController);
    mScrimController.setBackDropView(mBackdrop);
    mStatusBarView.setScrimController(mScrimController);
    mDozeScrimController = new DozeScrimController(mScrimController, context);

    mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
    mHeader.setActivityStarter(this);
    mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
    mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
    mKeyguardBottomArea =
            (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
    mKeyguardBottomArea.setActivityStarter(this);
    mKeyguardBottomArea.setAssistManager(mAssistManager);
    mKeyguardIndicationController = new KeyguardIndicationController(mContext,
            (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                    R.id.keyguard_indication_text));
    mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);

    // set the inital view visibility
    setAreThereNotifications();

    mIconController = new StatusBarIconController(
            mContext, mStatusBarView, mKeyguardStatusBar, this);

    // Background thread for any controllers that need it.
    mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
    mHandlerThread.start();

    // Other icons
    mLocationController = new LocationControllerImpl(mContext,
            mHandlerThread.getLooper()); // will post a notification
    mBatteryController = new BatteryController(mContext);
    mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
        @Override
        public void onPowerSaveChanged() {
            mHandler.post(mCheckBarModes);
            if (mDozeServiceHost != null) {
                mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
            }
        }
        @Override
        public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
            // noop
        }
    });
    mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
    mHotspotController = new HotspotControllerImpl(mContext);
    mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
    mSecurityController = new SecurityControllerImpl(mContext);
    if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
        mRotationLockController = new RotationLockControllerImpl(mContext);
    }
    mUserInfoController = new UserInfoController(mContext);
    mVolumeComponent = getComponent(VolumeComponent.class);
    if (mVolumeComponent != null) {
        mZenModeController = mVolumeComponent.getZenController();
    }
    mCastController = new CastControllerImpl(mContext);
    final SignalClusterView signalCluster =
            (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
    final SignalClusterView signalClusterKeyguard =
            (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
    final SignalClusterView signalClusterQs =
            (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
    mNetworkController.addSignalCallback(signalCluster);
    mNetworkController.addSignalCallback(signalClusterKeyguard);
    mNetworkController.addSignalCallback(signalClusterQs);
    signalCluster.setSecurityController(mSecurityController);
    signalCluster.setNetworkController(mNetworkController);
    signalClusterKeyguard.setSecurityController(mSecurityController);
    signalClusterKeyguard.setNetworkController(mNetworkController);
    signalClusterQs.setSecurityController(mSecurityController);
    signalClusterQs.setNetworkController(mNetworkController);
    final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
    if (isAPhone) {
        mNetworkController.addEmergencyListener(mHeader);
    }

    mFlashlightController = new FlashlightController(mContext);
    mKeyguardBottomArea.setFlashlightController(mFlashlightController);
    mKeyguardBottomArea.setPhoneStatusBar(this);
    mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
    mAccessibilityController = new AccessibilityController(mContext);
    mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
    mNextAlarmController = new NextAlarmController(mContext);
    mKeyguardMonitor = new KeyguardMonitor(mContext);
    if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
        mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
                mHandler);
    }
    mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
            (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
            mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);


    // Set up the quick settings tile panel
    mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
    if (mQSPanel != null) {
        final QSTileHost qsh = new QSTileHost(mContext, this,
                mBluetoothController, mLocationController, mRotationLockController,
                mNetworkController, mZenModeController, mHotspotController,
                mCastController, mFlashlightController,
                mUserSwitcherController, mKeyguardMonitor,
                mSecurityController);
        mQSPanel.setHost(qsh);
        mQSPanel.setTiles(qsh.getTiles());
        mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
        mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
        mHeader.setQSPanel(mQSPanel);
        qsh.setCallback(new QSTileHost.Callback() {
            @Override
            public void onTilesChanged() {
                mQSPanel.setTiles(qsh.getTiles());
            }
        });
    }

    // User info. Trigger first load.
    mHeader.setUserInfoController(mUserInfoController);
    mKeyguardStatusBar.setUserInfoController(mUserInfoController);
    mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
    mUserInfoController.reloadUserInfo();

    mHeader.setBatteryController(mBatteryController);
    ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
            mBatteryController);
    mKeyguardStatusBar.setBatteryController(mBatteryController);
    mHeader.setNextAlarmController(mNextAlarmController);

    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    mBroadcastReceiver.onReceive(mContext,
            new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));


    // receive broadcasts
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    filter.addAction(Intent.ACTION_SCREEN_ON);
    context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);

    IntentFilter demoFilter = new IntentFilter();
    if (DEBUG_MEDIA_FAKE_ARTWORK) {
        demoFilter.addAction(ACTION_FAKE_ARTWORK);
    }
    demoFilter.addAction(ACTION_DEMO);
    context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
            android.Manifest.permission.DUMP, null);

    // listen for USER_SETUP_COMPLETE setting (per-user)
    resetUserSetupObserver();

    // disable profiling bars, since they overlap and clutter the output on app windows
    ThreadedRenderer.overrideProperty("disableProfileBars", "true");

    // Private API call to make the shadows look better for Recents
    ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));

    return mStatusBarView;
}

![状态栏控件树的结构](http://upload-images.jianshu.io/upload_images/2043394-ddde815f8966729f?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

http://bbs.16rd.com/forum.php?mod=viewthread&tid=57808&highlight=recents

本文转自:

在Android4.0源码的frameworks/base/packages/SystemUI/res/drawable-mdpi/目录下增多ic_sysbar_screenshot.png文件,图片如下:

提及锁屏我们先来大概看下systemUI的运转流程

SystemUI常驻于系统,通过Service完毕,关键service:SystemUIService是在SystemServer.java中运营。

Android的运行分为基础运维,android运营,Launcher运营,大家的SystemServer就高居Android运营中,SystemUI的开发银行以下是大致流程:init->ServiceManager->Zygote->SystemServer->SystemUIService-->SystemUIApplication-->SystemUI.start(KeyguardViewMeditor,Recents等SytsemUI子类初阶融入的正规干活起来)

SystemUI具体的运行流程代码能够参照博客。

L Recent App风格相对于事先的版本变化异常的大,即使想在L版本贯彻KK版本的作风吗?

 

必威 1

规划代码

frameworks/base/packages/Keyguard

frameworks/base/packages/SystemUI

frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/ KeyguardServiceWrapper.java KeyguardServiceDelegate.java frameworks/base/core/java/android/app/keyguardManager.java packages/apps/Settings/src/com/android/settings/ChooseLockGeneric.java SecuritySettings.java

[SOLUTION]

Messenger:信使

该图片的背景是透明的PNG文件。

锁屏分类

那么锁屏分界面是怎么样加载到widnow显示出来的呢?首先须要分明的是6.0分为两类锁屏(非安全锁屏<滑动锁屏>和达州锁屏<图案和pin等>)

1.非康宁锁屏,称之为notification keyguard,那么些类型的keyguard 已经和statusbar融为一炉,能够经过PhoneStatusBar.java对象直接开展支配;

2.康宁锁屏,比方密码,图案,PIN码,PUK码等锁屏的锁屏分界面,通过keyguardBouncer.java进行调控

能够依据如下几步化解:
1、Recents.java里把上面包车型大巴flag true改为false:
// Which recents to use
boolean mUseALTErnateRecents = false; //true->false
2、修改ActivityRecord.java文件
Frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
final class ActivityRecord {
static final String TAG = ActivityManagerService.TAG;
static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
//去掉上边那句
final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
///新添下边那句
final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
3、修改 frameworks/base/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@Override
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
if (mUseAlternateRecents) {
sAlternateRecents.onHideRecents(triggeredFromAltTab, triggeredFromHomeKey);
} else {
///新添如下代码

官方文档解释:它援用了叁个Handler对象,以便others能够向它发送音信(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通讯(即多个进度间能够经过Message进行通讯),在服务端使用Handler创设二个Messenger,顾客端持有这么些Messenger就足以与服务端通讯了。

接下去修改frameworks/base/packages/SystemUI/res/layout-sw600dp/status_bar.xml文件,在

锁屏加载流程

  • if (triggeredFromHomeKey) {
  • Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
  • homeIntent.addCategory(Intent.CATEGORY_HOME);
  • homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  • | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    • mContext.startActivityAsUser(homeIntent, UserHandle.CURRENT);
  • }
    Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
    intent.setPackage("com.android.systemui");
    sendBroadcastSafely(intent);
    RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
    }
    }
    4、修改
    frameworks/base/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
    if (CLOSE_RECENTS_INTENT.equals(intent.getAction())) {
    if (mRecentsPanel != null && mRecentsPanel.isShowing()) {

 

android:layout_width="80dip"

非安全锁屏加载流程

首先非安全锁屏界面,是NotificationPanelView的一局地,在SystemUI运行SystemUI.start就已经加载,看下SystemUI开机运维流程图

必威 2

因为那边根本是锁屏,所以大家从PhoneStatusBar.start()开启看。

PhoneStatusBar.start会调用父类BaseStatusBar的start(),继续调用PhoneStatusBar的createAndAddWindow(),然后继续调用addStatusBarWindow来创设通告锁屏等StatusBarWindowView并加到window上。

非安全锁屏是NotificationPanelView的一局地,而NotificationPanelView又是StatusBarWindowView的一片段,所以这么就曾经将非安全情势加载好了,至于展现依旧隐敝就只是NotificationPanelView分界面调节的难题了,具体的View层级和决定代码量太多,暂不做深远深入分析

private void addStatusBarWindow() { makeStatusBarView(); mStatusBarWindowManager = new StatusBarWindowManager(mContext); mRemoteInputController = new RemoteInputController(mStatusBarWindowManager, mHeadsUpManager); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); }

伊始我们采纳Handler+Message的格局张开通讯,都以在同多个经过中,从线程持有二个主线程的Handler对象,并向主线程发送消息。

android:layout_height="match_parent"

康宁锁屏加载流程

有惊无险锁屏SystemUI运维时策画

地点还只是加载了非安全锁屏界面,那安全锁屏界面呢?实际上安全锁屏分界面也会加载到StatusBarWindowView,只可是是动态加载和移除,实际不是直接放在布局里最早化加载,大家大概看下锁屏UI层级

必威 3

在PhoneStatusBar.start()方法里加载完StatusBarWindowView后,还大概会调用startKeyGuard()来安全锁屏的片段初步化希图干活,这里关怀的是将StatusBarWindowView作为品质赋值给安全锁屏的操控类KeyguardBoncer

public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
        HeadsUpManager.OnHeadsUpChangedListener {
    @Override
    public void start() {
        super.start(); // calls createAndAddWindows()
        startKeyguard();
     }

    private void startKeyguard() {
        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
        //-----这里的mStatusBarWindow就是StatusBarWindowView
        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                mStatusBarWindow, mStatusBarWindowManager, mScrimController);
        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
    }
}

public class KeyguardViewMediator extends SystemUI {
    public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
            ScrimController scrimController) {
        //-----这里的container就是StatusBarWindowView       
        mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
                statusBarWindowManager, scrimController);
        return mStatusBarKeyguardViewManager;
    }
}
 
public class StatusBarKeyguardViewManager {
    public void registerStatusBar(PhoneStatusBar phoneStatusBar,
            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
            ScrimController scrimController) {
        mPhoneStatusBar = phoneStatusBar;
        mContainer = container;
        mStatusBarWindowManager = statusBarWindowManager;
        mScrimController = scrimController;
        mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
                mStatusBarWindowManager, container);
        mKeyguardMusicManager = KeyguardMusicManager.getInstance(mContext, this);
    }
}

public class KeyguardBouncer {
    public KeyguardBouncer(Context context, ViewMediatorCallback callback,
            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
            ViewGroup container) {
        mContext = context;
        mCallback = callback;
        mLockPatternUtils = lockPatternUtils;
        mContainer = container;//-----那样就将StatusBarWindowView作为品质赋值给安全锁屏的操控类
        mWindowManager = windowManager;
    }
}

  • if (mShowing && !mForeground) {//去掉那行
    ///新扩大如下代码

而Android既然能够应用bindler机制实行跨举行通讯,所以大家本来能够将Handler与bindler结合起来实行跨进度发送消息。

android:src="@drawable/ic_sysbar_screenshot"

有惊无险锁屏开机浮现流程

查阅API就能够开采,Messenger就是这种措施的兑现。

android:contentDescription="@string/accessibility_screenshot"

时序图

到今日达成还只是StatusBarWindowView与KeyguardBouncer关联,那安全锁屏分界面到底是何等时候加载到StatusBarWindowView进而展现给大家吧?实际上大家前边也说了,安全锁屏分界面其实是动态的加载和移除的,从未上锁到上锁就能够addView,实现整个解锁就可以removeView,比方开机完毕后就能够上锁,下边大家来深入分析下开机体现安全锁屏流程,首先看下时序图:

必威 4

必威 5

  • if (mShowing) {
    // Captures the case right before we transition to another activity
    mRecentsPanel.show(false);
  • if (mForeground) {
  • finish();
  • }
    }
    }
    } else if (WINDOW_ANIMATION_START_INTENT.equals(intent.getAction())) {
    if (mRecentsPanel != null) {
    mRecentsPanel.onWindowAnimationStart();
    }
    }
    }
    };</font></font>

貌似接纳办法如下:

systemui:glowBackground="@drawable/ic_sysbar_highlight"

代码流程

开机运行流程其实也很复杂,可是本文珍视在于KeyGuard锁屏的显示,所以大家从开机运维调用到PhoneWindowManager的SystemReady()和SystemReady()和SystemBooted()方法开首解析。

systemReady()调用systemBooted()以前,至于实际的调用流程这里不做解析,大概也是SystemServer.java中main函数会调用startOtherService()方法跟下去:

那么今后看下来PhoneWindowManager的systemReady()和systemBooted()这四个章程

public class PhoneWindowManager implements WindowManagerPolicy {
    @Override
    public void systemReady() {
        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
        mKeyguardDelegate.onSystemReady();
        boolean bindKeyguardNow;
        synchronized (mLock) {
            bindKeyguardNow = mDeferBindKeyguard;
            if (bindKeyguardNow) {
                // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
                mDeferBindKeyguard = false;
            }
        }
        if (bindKeyguardNow) {
            mKeyguardDelegate.bindService(mContext);
            mKeyguardDelegate.onBootCompleted();
        }
    }
   
    @Override
    public void systemBooted() {
        
        boolean bindKeyguardNow = false;
        synchronized (mLock) {
            // Time to bind Keyguard; take care to only bind it once, either here if ready or
            // in systemReady if not.
            if (mKeyguardDelegate != null) {
                bindKeyguardNow = true;
            } else {
                // Because mKeyguardDelegate is null, we know that the synchronized block in
                // systemReady didn't run yet and setting this will actually have an effect.
                mDeferBindKeyguard = true;
            }
        }
        if (bindKeyguardNow) {
            mKeyguardDelegate.bindService(mContext);
            mKeyguardDelegate.onBootCompleted();
        }
 }

看代码可见,systemReady()方法里最初化KeyguardServiceDeleGate,但还不能够bindService,等到systemBooted()时才具bindService,上边bindService做了些什么

public class KeyguardServiceDelegate {
    protected KeyguardServiceWrapper mKeyguardService;

    public void bindService(Context context) {
        Intent intent = new Intent();
        //-----config_keyguardComponent就是com.android.systemui/com.android.systemui.keyguard.KeyguardService
        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                resources.getString(com.android.internal.R.string.config_keyguardComponent));
        intent.setComponent(keyguardComponent);
        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {}
    }

    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mKeyguardService = new KeyguardServiceWrapper(mContext,
                    IKeyguardService.Stub.asInterface(service));
            if (mKeyguardState.systemIsReady) {
                // If the system is ready, it means keyguard crashed and restarted.
                mKeyguardService.onSystemReady();//-----前边调用systemReady,所以那边成立
                // This is used to hide the scrim once keyguard displays.
                mKeyguardService.onStartedWakingUp()
                mKeyguardService.onScreenTurningOn(
                        new KeyguardShowDelegate(mDrawnListenerWhenConnect));
                mKeyguardService.onScreenTurnedOn();
                mDrawnListenerWhenConnect = null;
            }
            if (mKeyguardState.bootCompleted) {
                mKeyguardService.onBootCompleted();
            }
            if (mKeyguardState.occluded) {
                mKeyguardService.setOccluded(mKeyguardState.occluded);
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
            mKeyguardService = null;
        }

    };
 }

因为config_keyguardComponent就是com.android.systemui/com.andoid.systemui.keyguard.KeyguardService,所以IKeyguardService.Stub.asInterface(service)就是KeyguardService里的private final IKeyguard瑟维斯.Stub mBinder,约等于KeyguardServiceWrapper里的private IKeyguard瑟维斯mService,所以随后调用onSystemReady()

public class KeyguardServiceWrapper implements IKeyguardService {
    private IKeyguardService mService;

    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
        mService = service;
    }

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

于是乎再走到KeyguardService.mBinder.onSystemReady()

public class KeyguardService extends Service {
    private KeyguardViewMediator mKeyguardViewMediator;
    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
        @Override // Binder interface
        public void onSystemReady() {
            checkPermission();
            mKeyguardViewMediator.onSystemReady();
        }
    }
}

好不轻松走到大家锁屏模块最要紧的调节类KeyguardViewMediator,功效上顶住管理keyguard试图的事件,锁屏事件的输入,上面继续KeyguardViewMediator的doKeyguardLocked()

public class KeyguardViewMediator extends SystemUI {
    public void onSystemReady() {
            doKeyguardLocked(null);
    }

    private void doKeyguardLocked(Bundle options) {
        showLocked(options);
    }

    private void showLocked(Bundle options) {
        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);
    }

    private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW:
                    handleShow((Bundle) msg.obj);
                    break;
            }
        }
    };

    private void handleShow(Bundle options) {
            mStatusBarKeyguardViewManager.show(options);
    }
   
}

因此代码可见,最终将show动作交给StatusBarkeyguardViewManager来管理,实际上那类直接锁屏相关动作最终都会付出StatusbarKeyguardViewManager管理,StatusBarKeyguardViewManager正是keyguard的视图管理者,包涵非安全锁屏和乌海锁屏,接着往下看

public class StatusBarKeyguardViewManager {
     private PhoneStatusBar mPhoneStatusBar;
     private KeyguardBouncer mBouncer;
     /**
     * Show the keyguard.  Will handle creating and attaching to the view manager
     * lazily.
     */
    public void show(Bundle options) {
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        mScrimController.abortKeyguardFadingOut();
        reset();//-----show和reset动作都会调用reset
        mKeyguardMusicManager.start();
    }

    /**
     * Reset the state of the view.
     */
    public void reset() {
        if (mShowing) {
            if (mOccluded) {
                mPhoneStatusBar.hideKeyguard();
                mPhoneStatusBar.stopWaitingForKeyguardExit();
                mBouncer.hide(false /* destroyView */);
            } else {
                showBouncerOrKeyguard();//-----展现安全锁屏分界面照旧先出示非安全锁屏分界面
            }
            KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
            updateStates();
        }
    }

    /**
     * Shows the notification keyguard or the bouncer depending on
     * {@link KeyguardBouncer#needsFullscreenBouncer()}.
     */
    private void showBouncerOrKeyguard() {
        if (mBouncer.needsFullscreenBouncer()) {

            // The keyguard might be showing (already). So we need to hide it.
            mPhoneStatusBar.hideKeyguard();
            mBouncer.show(true /* resetSecuritySelection */);
        } else {
            mPhoneStatusBar.showKeyguard();
            mBouncer.hide(false /* destroyView */);
            mBouncer.prepare();
        }
    }
}

在showBouncerOrKeyguard方法里mPhoneStatusBar.hideKeyguard()和mPhoneStatusBar.showKeyguard;调整的是非安全锁,而mBoncer.show(true)和mBoncer.hide(false)调控的是平安锁屏,也正是说非安全锁屏和平安锁屏在这里伊始分级由PhoneStatusBar和KeyguardBouncer管理,前边说了非安全锁屏这里不做升入剖析,上面入眼看安全锁屏,安全锁屏分界面KeyguardHostView作为KeyguardBouncer的属性直接被操控,而要不要先出示非安全锁屏是依据锁屏方式来的,由于锁屏景况太多未来要是是丹青解锁,具体在往下来,依照当下情景来看是会走到

/**
 * A class which manages the bouncer on the lockscreen.
 */
public class KeyguardBouncer {

    private KeyguardHostView mKeyguardView;
    /**
     * @return True if and only if the security method should be shown before showing the
     * notifications on Keyguard, like SIM PIN/PUK.
     */
    public boolean needsFullscreenBouncer() {
        ensureView();//-----a
        if (mKeyguardView != null) {
            SecurityMode mode = mKeyguardView.getSecurityMode();
            return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;//-----c
        }
        return false;
    }

    public void show(boolean resetSecuritySelection) {//-----实际上彰显、重新设置、移除动作都会调用到
        ensureView();//----确认保障卫安全全锁屏分界面有创制并增加到StatusBarWindowView上,何况安全分界面早先化时是不可知的INVISIBLE

        if (resetSecuritySelection) {//-----是或不是必要重新初始化安全分界面
            // showPrimarySecurityScreen() updates the current security method. This is needed in
            // case we are already showing and the current security method changed.
            mKeyguardView.showPrimarySecurityScreen();//-----d
        }
        if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {//-----mRoot是安全锁屏界面,当已是可知是return,举个例子重新设置
            return;
        }
        // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
        // Keyguard. If we need to authenticate, show the bouncer.
        if (!mKeyguardView.dismiss()) {//-----试图移除锁屏分界面,比如刚上锁,安全分界面还不可知//-----e
            mShowingSoon = true; // Split up the work over multiple frames.
            DejankUtils.postAfterTraversal(mShowRunnable);//-----安全分界面设置成可知VISIBLE//-----f
        }
    }

    private final Runnable mShowRunnable = new Runnable() {
        @Override
        public void run() {
            mRoot.setVisibility(View.VISIBLE);
            mKeyguardView.onResume();
            showPromptReason(mBouncerPromptReason);
            mKeyguardView.startAppearAnimation();
            mShowingSoon = false;
            mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
        }
    };

    private void ensureView() {
        if (mRoot == null) {//-----安全分界面跟布局,一般无锁到有锁起初化,完全到位解锁时置空
            inflateView();//-----b
        }
    }

    private void inflateView() {
        removeView();
        mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
        mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
        mKeyguardView.setViewMediatorCallback(mCallback);
        mContainer.addView(mRoot, mContainer.getChildCount());
        mRoot.setVisibility(View.INVISIBLE);
        mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
    }

}

随即看mKeyguardView.showPrimarySecurityScreen(),KeyguardHostView是平安锁屏主分界面,达成了SecrityCallBack接口,其余地点使用的SeurityCakkback其实正是KeyguardHostview

public class KeyguardHostView extends FrameLayout implements SecurityCallback {
    private KeyguardSecurityContainer mSecurityContainer;
        /**
     * Called when the view needs to be shown.
     */
    public void showPrimarySecurityScreen() {
        if (DEBUG) Log.d(TAG, "show()");
        mSecurityContainer.showPrimarySecurityScreen(false);
    }
}

KeyguardSecurityContainer,安全锁屏View的容,会实际依据安全形式展示区别的View,继续往上边

public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
    private KeyguardSecurityViewFlipper mSecurityViewFlipper;//安全view的父布局

    /**
     * Shows the primary security screen for the user. This will be either the multi-selector
     * or the user's security method.
     * @param turningOff true if the device is being turned off
     */
    void showPrimarySecurityScreen(boolean turningOff) {
        SecurityMode securityMode = mSecurityModel.getSecurityMode();//----获取安全情势
        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);//----将安全view增多到父布局<span></span>KeyguardSecurityViewFlipper进而到<span></span>KeyguardSecurityContainer上
            updateSecurityView(v);
            view = (KeyguardSecurityView)v;
        }

        return view;
    }

}

到日前地方通过mSercutityViewFliper.addView(v);最后将安全view增多到StatusBarWindowView,不过安全锁屏跟布局依然不可知的,所以代码走到KeyguardBouncer的处,那么mKeyguardView.dismiss()又做了哪些吗,继续往下跟

public class KeyguardHostView extends FrameLayout implements SecurityCallback {
    /**
     *  Dismisses the keyguard by going to the next screen or making it gone.
     *
     *  @return True if the keyguard is done.
     */
    public boolean dismiss() {
        return dismiss(false);
    }

    @Override
    public boolean dismiss(boolean authenticated) {
        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
    }
}

行吗,又是KeyguardSecurityContainer,当前处境下参数未false,继续往下看:

/**
     * Shows the next security screen if there is one.
     * @param authenticated true if the user entered the correct authentication
     * @return true if keyguard is done
     */
    //-----展现下贰个乌兰察布锁屏分界面,参数十分重大,参数表示是或不是通过证实
    boolean showNextSecurityScreenOrFinish(boolean authenticated) {
        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
        boolean finish = false;
        if (mUpdateMonitor.getUserCanSkipBouncer(
                KeyguardUpdateMonitor.getCurrentUser())) {
            //-----能够跳过安全锁屏,直接完全具备锁屏
            finish = true;
        } else if (SecurityMode.None == mCurrentSecuritySelection) {
            //当前是非安全锁屏(滑动),获取下三个锁屏情势,假如如故非安全锁屏(滑动),直接完全具有锁屏,不然呈现下一个平安锁屏界面
            SecurityMode securityMode = mSecurityModel.getSecurityMode();
            if (SecurityMode.None == securityMode) {
                finish = true; // no security required
            } else {
                showSecurityScreen(securityMode); // switch to the alternate security view
            }
        } else if (authenticated) {
            //-----假若是因此认证的,当前的是普普通通的安全格局,那么成功总体解锁,要是是pinpuk之类的第三类动态的就无冕合检查查下一个锁屏,
            //-----下一个是平安锁屏就三番五次展现下一个龙井锁屏分界面,不然实现全体解锁
            switch (mCurrentSecuritySelection) {
                case Pattern:
                case Password:
                case PIN:
                    finish = true;
                    break;

                case SimPin:
                case SimPuk:
                    // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                    SecurityMode securityMode = mSecurityModel.getSecurityMode();
                    if (securityMode != SecurityMode.None
                            || !mLockPatternUtils.isLockScreenDisabled(
                            KeyguardUpdateMonitor.getCurrentUser())) {
                        showSecurityScreen(securityMode);
                        /* SPRD:add PIN verify success prompt @{ */
                        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
                        if (oldView != null) {
                            oldView.onPause();
                        }
                        /* @} */
                    } else {
                        finish = true;
                    }
                    break;

                default:
                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
                    showPrimarySecurityScreen(false);
                    break;
            }
        }
        if (finish) {
            //-----达成了全体解锁,下边要早先rm安全分界面等局地操作,mSecurityCallback正是KeyguardHostView
            mSecurityCallback.finish();
        }
        return finish;
    }

脚下光景下都不满意,直接重回false,那么代码继续走到KeyguardBouncer的处,也正是把平安锁屏根布局设置为可知mRoot.setVisibility(View.VISIBLE);最后锁屏控件都已加载到StatusBarWindowView上且可知

|

1。远程通过

/>

锁屏调用入口

别的场景,如解锁,灭屏等遵照上面包车型大巴思绪结构都很轻巧深入分析就不再赘述,调用入口方今如下两种状态;

1KeyguardSecurityCallBack.dismiss(true)-->KeyguardSecurityContainer.SecurityCallback.dismiss(true)-->实际上对象就是KeyguardHostView.dismiss(true)-->......那中一般是解锁了安全锁屏onClick里

2ViewMeditorCallback-->实际目标正是KeyguardViewMeditor.mViewMeditorCallback

这种一般是应用内平昔调用,比方增多手提式有线电话机防盗解锁,受到上锁广播时直接调用showLocked(null)或resetStatLocked()

3、KeyguardServiceDelegate-->绑定KeyguardService       

<permission android:name="com.android.systemui.permission.SELF"             android:protectionLevel="signature" />      

signature:这种权力等级,唯有当发央求的行使和摄取此恳请的采纳使用一样签字文件,并且评释了该权限才会授权,而且是暗许授权,不会唤起客商授权       这种一般是frameworks通过binder服务调用,如开机上锁,灭屏上锁等 

4、通过品质android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUAR                       android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKE    

其三方使用一般因为权限难点经过品质来决定化解非安全锁屏或分界面展现在锁之上

 

接下去修改frameworks/base/packages/SystemUI/res/values/strings.xml文件,增添如下内容:

总结

谈起底关于锁屏再总计一下:

ui层级图

必威 6

UI时序图

1、锁屏分两类:非安全锁屏(如滑动锁屏)和安全锁屏(滑动锁屏)

2、他们都会加载到StatusBarWindowView上,而StatusBarWindowView在又会加载到window上之所以展现出来

3、不相同的是: 非安全锁屏在PanelHolder上,是StatusBarWindowView布局的一有个别,所以随着开机加载systemui时就能加载上去,通过开展折叠等布局调控来显示与否 而平安锁屏是KeyguardHostView,它实际不是StatusBarWindowView原有布局的一片段,而是基于上锁和平化解锁实际情形来动态加载和移除以及安装可知与不可知来显示与否,第一回加载是在成就开机动画触屏可兆示时

Java代码 必威 7 必威 8必威 9)

ScreenShot

  1. mMessenger = new Messenger(mHandler)  

迄今截止,重新编写翻译烧录源码,在气象栏上会多出截屏Logo,接下去供给三番五次贯彻截屏成效,查看了frameworks里的源码,找到了frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java文件里有可参看的片断,故继续修改frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java文件,相应的增加如下内容:

 

import android.os.Messenger;

mMessenger = new Messenger(mHandler)

import android.content.ComponentName;

 创制叁个信使对象

import android.content.ServiceConnection;

2。客户端应用bindlerService央浼连接远程

在View mRecentButton;后边增添View mScreenshotButton;语句。

3。远程onBind方法再次回到多个bindler

在mRecentButton.setOnClickListener(mOnClickListener);后增加如下内容:

 

mScreenshotButton = mNavigationArea.findViewById(R.id.my_screenshot);

Java代码 必威 10 必威 11必威 12)

TAG标签:
版权声明:本文由必威发布于必威-编程,转载请注明出处:systemui包括了系统栏和导航栏,必威:以前我们使