最近在学习Android 4.4上面的WifiDisplay(Miracast)相关的模块,这里先从WifiDisplay用到的各个Service讲起,然后再从WifiDisplaySettings里面讲解打开wfd的流程。首先看下面的主要几个Service的架构图:
图中主要有以下几个模块,DisplayManagerService、MediaRouterService、WifiDisplayAdapter和WifiDisplayController。其中:
DisplayManagerService用于管理系统显示设备的生命周期,包含物理屏幕、虚拟屏幕、wifi display等,它用一组DiaplayAdapter来管理这些显示设备。
MediaRouterService用于管理各个应用程序的多媒体播放的行为。
MediaRouter用于和MediaRouterService交互一起管理多媒体的播放行为,并维护当前已经配对上的remote display设备,包括Wifi diplay、蓝牙A2DP设备、chromecast设备。
WifiDisplayAdapter是用于DisplayManagerService管理Wifi display显示的adapter。
WifiDisplayController用于控制扫描wifi display设备、连接、断开等操作。
先来顺着上面的架构图看各个Service的启动。首先来看DisplayManagerService,在SystemServer中先创建一个DisplayManagerService对象,然后调用systemReady方法:
public DisplayManagerService(Context context, Handler mainHandler) { mContext = context; mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1"); mHandler = new DisplayManagerHandler(mainHandler.getLooper()); mUiHandler = UiThread.getHandler(); mDisplayAdapterListener = new DisplayAdapterListener(); mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER); } public void systemReady(boolean safeMode, boolean onlyCore) { synchronized (mSyncRoot) { mSafeMode = safeMode; mOnlyCore = onlyCore; } mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS); }
private final class DisplayManagerHandler extends Handler { public DisplayManagerHandler(Looper looper) { super(looper, null, true /*async*/); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER: registerDefaultDisplayAdapter(); break; case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS: registerAdditionalDisplayAdapters(); break;
private void registerDefaultDisplayAdapter() { // Register default display adapter. synchronized (mSyncRoot) { if (mHeadless) { registerDisplayAdapterLocked(new HeadlessDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); } else { registerDisplayAdapterLocked(new LocalDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener)); } } } private void registerDisplayAdapterLocked(DisplayAdapter adapter) { mDisplayAdapters.add(adapter); adapter.registerLocked(); }
private void registerAdditionalDisplayAdapters() { synchronized (mSyncRoot) { if (shouldRegisterNonEssentialDisplayAdaptersLocked()) { registerOverlayDisplayAdapterLocked(); registerWifiDisplayAdapterLocked(); registerVirtualDisplayAdapterLocked(); } } }
private void registerWifiDisplayAdapterLocked() { if (mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableWifiDisplay) || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) { mWifiDisplayAdapter = new WifiDisplayAdapter( mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mPersistentDataStore); registerDisplayAdapterLocked(mWifiDisplayAdapter); } }
public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, PersistentDataStore persistentDataStore) { super(syncRoot, context, handler, listener, TAG); mHandler = new WifiDisplayHandler(handler.getLooper()); mPersistentDataStore = persistentDataStore; mSupportsProtectedBuffers = context.getResources().getBoolean( com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers); mNotificationManager = (NotificationManager)context.getSystemService( Context.NOTIFICATION_SERVICE); } public void registerLocked() { super.registerLocked(); updateRememberedDisplaysLocked(); getHandler().post(new Runnable() { @Override public void run() { mDisplayController = new WifiDisplayController( getContext(), getHandler(), mWifiDisplayListener); getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, new IntentFilter(ACTION_DISCONNECT), null, mHandler); } }); }
public WifiDisplayController(Context context, Handler handler, Listener listener) { mContext = context; mHandler = handler; mListener = listener; mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler); ContentObserver settingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { updateSettings(); } }; final ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver); resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, settingsObserver); resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, settingsObserver); updateSettings(); }
这里主要注册WifiP2pReceiver用于接收处理WIFI_P2P_STATE_CHANGED_ACTION、WIFI_P2P_PEERS_CHANGED_ACTION、WIFI_P2P_CONNECTION_CHANGED_ACTION、WIFI_P2P_THIS_DEVICE_CHANGED_ACTION消息,然后注册ContentObserver来监控Settings.Global这个数据库里面的WIFI_DISPLAY_ON、WIFI_DISPLAY_CERTIFICATION_ON和WIFI_DISPLAY_WPS_CONFIG,这里比较重要,我们后面会看到在WifiDisplaySettings里面enable wifi display的时候,就会走到这个地方来。接着调用updateSettings来处理默认是否打开Wifi display,这里默认是关闭的,我们后面再来分析这一块。
接着来看MediaRouterService和MediaRouter,MediaRouter通过AIDL调用MediaRouterService的实现来完成一些工作。在SystemServer启动MediaRouterService的时候,主要创建一个MediaRouterService,然后调用它的systemRunning方法,代码如下:
public MediaRouterService(Context context) { mContext = context; Watchdog.getInstance().addMonitor(this); } public void systemRunning() { IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) { switchUser(); } } }, filter); switchUser(); }
A MediaRouter is retrieved through Context.getSystemService()
of a Context.MEDIA_ROUTER_SERVICE
. 这样系统是实例化一个MediaRouter对象并返回,下面来看它的构造函数:
public MediaRouter(Context context) { synchronized (Static.class) { if (sStatic == null) { final Context appContext = context.getApplicationContext(); sStatic = new Static(appContext); sStatic.startMonitoringRoutes(appContext); } } } Static(Context appContext) { mAppContext = appContext; mResources = Resources.getSystem(); mHandler = new Handler(appContext.getMainLooper()); IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); mAudioService = IAudioService.Stub.asInterface(b); mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE); mMediaRouterService = IMediaRouterService.Stub.asInterface( ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); mSystemCategory = new RouteCategory( com.android.internal.R.string.default_audio_route_category_name, ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false); mSystemCategory.mIsSystem = true; mCanConfigureWifiDisplays = appContext.checkPermission( Manifest.permission.CONFIGURE_WIFI_DISPLAY, Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; }
void startMonitoringRoutes(Context appContext) { mDefaultAudioVideo = new RouteInfo(mSystemCategory); mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name; mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO; mDefaultAudioVideo.updatePresentationDisplay(); addRouteStatic(mDefaultAudioVideo); // This will select the active wifi display route if there is one. updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus()); appContext.registerReceiver(new WifiDisplayStatusChangedReceiver(), new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)); appContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); mDisplayService.registerDisplayListener(this, mHandler); // Bind to the media router service. rebindAsUser(UserHandle.myUserId()); // Select the default route if the above didn't sync us up // appropriately with relevant system state. if (mSelectedRoute == null) { selectDefaultRouteStatic(); } }
首先注册系统中默认的AudioVideo输出设备,如果有处于活动状态的wifi display连接,就记录下当前处于活动连接的设备,默认为空。上面会注册两个broadcastReceiver,一个用于接收ACTION_WIFI_DISPLAY_STATUS_CHANGED,另一个接收VOLUME_CHANGED_ACTION,我们主要看前面接收ACTION_WIFI_DISPLAY_STATUS_CHANGED的receiver,如下:
static class WifiDisplayStatusChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra( DisplayManager.EXTRA_WIFI_DISPLAY_STATUS)); } }上面接收ACTION_WIFI_DISPLAY_STATUS_CHANGED,从Intent里面取出WifiDisplayStatus对象,WifiDisplayStatus内部的变量如下:
mFeatureState | 表明现在wifi display是关闭还是打开状态 |
mScanState | 表现现在wifi display是否在scanning状态 |
mActiveDisplayState | 表明现在wifi display是在连接还是无连接状态 |
mActiveDisplay | 处于正在连接或者连接中的WifiDisplay对象 |
mDisplays | 扫描到的WifiDisplay对象数组 |
mSessionInfo | 用于过Miracast认证时用 |
然后向DisplayManager注册一个回调函数,当有显示设备增加、删除或者改变的时候,就会有相应的回调函数来通知Static对象。接着绑定MediaRouterService:
void rebindAsUser(int userId) { if (mCurrentUserId != userId || userId < 0 || mClient == null) { mCurrentUserId = userId; try { Client client = new Client(); mMediaRouterService.registerClientAsUser(client, mAppContext.getPackageName(), userId); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router client.", ex); } publishClientDiscoveryRequest(); publishClientSelectedRoute(false); updateClientState(); } }
public void onCreate(Bundle icicle) { super.onCreate(icicle); final Context context = getActivity(); mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE); mWifiP2pChannel = mWifiP2pManager.initialize(context, Looper.getMainLooper(), null); addPreferencesFromResource(R.xml.wifi_display_settings); setHasOptionsMenu(true); } public void onStart() { super.onStart(); mStarted = true; final Context context = getActivity(); IntentFilter filter = new IntentFilter(); filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED); context.registerReceiver(mReceiver, filter); getContentResolver().registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_ON), false, mSettingsObserver); getContentResolver().registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON), false, mSettingsObserver); getContentResolver().registerContentObserver(Settings.Global.getUriFor( Settings.Global.WIFI_DISPLAY_WPS_CONFIG), false, mSettingsObserver); mRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mRouterCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); update(CHANGE_ALL); }
public void addCallback(int types, Callback cb, int flags) { CallbackInfo info; int index = findCallbackInfo(cb); if (index >= 0) { info = sStatic.mCallbacks.get(index); info.type |= types; info.flags |= flags; } else { info = new CallbackInfo(cb, types, flags, this); sStatic.mCallbacks.add(info); } sStatic.updateDiscoveryRequest(); }
void updateDiscoveryRequest() { final int count = mCallbacks.size(); for (int i = 0; i < count; i++) { CallbackInfo cbi = mCallbacks.get(i); if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) { // Discovery explicitly requested. routeTypes |= cbi.type; } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) { // Discovery only passively requested. passiveRouteTypes |= cbi.type; } else { // Legacy case since applications don't specify the discovery flag. // Unfortunately we just have to assume they always need discovery // whenever they have a callback registered. routeTypes |= cbi.type; } if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) { activeScan = true; if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) { activeScanWifiDisplay = true; } } } if (routeTypes != 0 || activeScan) { // If someone else requests discovery then enable the passive listeners. // This is used by the MediaRouteButton and MediaRouteActionProvider since // they don't receive lifecycle callbacks from the Activity. routeTypes |= passiveRouteTypes; } // Update wifi display scanning. // TODO: All of this should be managed by the media router service. if (mCanConfigureWifiDisplays) { if (mSelectedRoute != null && mSelectedRoute.matchesTypes(ROUTE_TYPE_REMOTE_DISPLAY)) { // Don't scan while already connected to a remote display since // it may interfere with the ongoing transmission. activeScanWifiDisplay = false; } if (activeScanWifiDisplay) { if (!mActivelyScanningWifiDisplays) { mActivelyScanningWifiDisplays = true; mDisplayService.startWifiDisplayScan(); } } else { if (mActivelyScanningWifiDisplays) { mActivelyScanningWifiDisplays = false; mDisplayService.stopWifiDisplayScan(); } } } }
private void updateScanState() { if (mScanRequested && mWfdEnabled && mDesiredDevice == null) { if (!mDiscoverPeersInProgress) { Slog.i(TAG, "Starting Wifi display scan."); mDiscoverPeersInProgress = true; handleScanStarted(); tryDiscoverPeers(); } } else { if (mDiscoverPeersInProgress) { // Cancel automatic retry right away. mHandler.removeCallbacks(mDiscoverPeers); if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) { Slog.i(TAG, "Stopping Wifi display scan."); mDiscoverPeersInProgress = false; stopPeerDiscovery(); handleScanFinished(); } } } }
public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ID_ENABLE_WIFI_DISPLAY: mWifiDisplayOnSetting = !item.isChecked(); item.setChecked(mWifiDisplayOnSetting); Settings.Global.putInt(getContentResolver(), Settings.Global.WIFI_DISPLAY_ON, mWifiDisplayOnSetting ? 1 : 0);
private void updateSettings() { final ContentResolver resolver = mContext.getContentResolver(); mWifiDisplayOnSetting = Settings.Global.getInt(resolver, Settings.Global.WIFI_DISPLAY_ON, 0) != 0; mWifiDisplayCertMode = Settings.Global.getInt(resolver, Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON, 0) != 0; mWifiDisplayWpsConfig = WpsInfo.INVALID; if (mWifiDisplayCertMode) { mWifiDisplayWpsConfig = Settings.Global.getInt(resolver, Settings.Global.WIFI_DISPLAY_WPS_CONFIG, WpsInfo.INVALID); } updateWfdEnableState(); }
private void updateWfdEnableState() { if (mWifiDisplayOnSetting && mWifiP2pEnabled) { // WFD should be enabled. if (!mWfdEnabled && !mWfdEnabling) { mWfdEnabling = true; WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo(); wfdInfo.setWfdEnabled(true); wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE); wfdInfo.setSessionAvailable(true); wfdInfo.setControlPort(DEFAULT_CONTROL_PORT); wfdInfo.setMaxThroughput(MAX_THROUGHPUT); mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() { @Override public void onSuccess() { if (DEBUG) { Slog.d(TAG, "Successfully set WFD info."); } if (mWfdEnabling) { mWfdEnabling = false; mWfdEnabled = true; reportFeatureState(); updateScanState(); } } @Override public void onFailure(int reason) { if (DEBUG) { Slog.d(TAG, "Failed to set WFD info with reason " + reason + "."); } mWfdEnabling = false; } }); }
private void reportFeatureState() { final int featureState = computeFeatureState(); mHandler.post(new Runnable() { @Override public void run() { mListener.onFeatureStateChanged(featureState); } }); } private int computeFeatureState() { if (!mWifiP2pEnabled) { return WifiDisplayStatus.FEATURE_STATE_DISABLED; } return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON : WifiDisplayStatus.FEATURE_STATE_OFF; }
public void onFeatureStateChanged(int featureState) { synchronized (getSyncRoot()) { if (mFeatureState != featureState) { mFeatureState = featureState; scheduleStatusChangedBroadcastLocked(); } } } private void scheduleStatusChangedBroadcastLocked() { mCurrentStatus = null; if (!mPendingStatusChangeBroadcast) { mPendingStatusChangeBroadcast = true; mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST); } }
public void handleMessage(Message msg) { switch (msg.what) { case MSG_SEND_STATUS_CHANGE_BROADCAST: handleSendStatusChangeBroadcast(); break; case MSG_UPDATE_NOTIFICATION: handleUpdateNotification(); break; } private void handleSendStatusChangeBroadcast() { final Intent intent; synchronized (getSyncRoot()) { if (!mPendingStatusChangeBroadcast) { return; } mPendingStatusChangeBroadcast = false; intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS, getWifiDisplayStatusLocked()); } // Send protected broadcast about wifi display status to registered receivers. getContext().sendBroadcastAsUser(intent, UserHandle.ALL); }
private void updateScanState() { if (mScanRequested && mWfdEnabled && mDesiredDevice == null) { if (!mDiscoverPeersInProgress) { Slog.i(TAG, "Starting Wifi display scan."); mDiscoverPeersInProgress = true; handleScanStarted(); tryDiscoverPeers(); } }
private void tryDiscoverPeers() { mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() { @Override public void onSuccess() { if (DEBUG) { Slog.d(TAG, "Discover peers succeeded. Requesting peers now."); } if (mDiscoverPeersInProgress) { requestPeers(); } } mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS); }
private void requestPeers() { mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList peers) { if (DEBUG) { Slog.d(TAG, "Received list of peers."); } mAvailableWifiDisplayPeers.clear(); for (WifiP2pDevice device : peers.getDeviceList()) { if (DEBUG) { Slog.d(TAG, " " + describeWifiP2pDevice(device)); } if (isWifiDisplay(device)) { mAvailableWifiDisplayPeers.add(device); } } if (mDiscoverPeersInProgress) { handleScanResults(); } } }); }
private void handleScanResults() { final int count = mAvailableWifiDisplayPeers.size(); final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count); for (int i = 0; i < count; i++) { WifiP2pDevice device = mAvailableWifiDisplayPeers.get(i); displays[i] = createWifiDisplay(device); updateDesiredDevice(device); } mHandler.post(new Runnable() { @Override public void run() { mListener.onScanResults(displays); } }); }
mDeviceAddress | 设备的Mac地址 |
mDeviceName | 设备的名字 |
mDeviceAlias | 设备的别名,一般为NULL |
mIsAvailable | 是否可用状态 |
mCanConnect | WfdInfo中的SessionAvailable是否为1 |
mIsRemembered | 是否被记录的 |
public void onScanResults(WifiDisplay[] availableDisplays) { synchronized (getSyncRoot()) { availableDisplays = mPersistentDataStore.applyWifiDisplayAliases( availableDisplays); boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays); // Check whether any of the available displays changed canConnect status. for (int i = 0; !changed && i<availableDisplays.length; i++) { changed = availableDisplays[i].canConnect() != mAvailableDisplays[i].canConnect(); } if (changed) { mAvailableDisplays = availableDisplays; fixRememberedDisplayNamesFromAvailableDisplaysLocked(); updateDisplaysLocked(); scheduleStatusChangedBroadcastLocked(); } } }
public WifiDisplay[] applyWifiDisplayAliases(WifiDisplay[] displays) { WifiDisplay[] results = displays; if (results != null) { int count = displays.length; for (int i = 0; i < count; i++) { WifiDisplay result = applyWifiDisplayAlias(displays[i]); if (result != displays[i]) { if (results == displays) { results = new WifiDisplay[count]; System.arraycopy(displays, 0, results, 0, count); } results[i] = result; } } } return results; }
private void fixRememberedDisplayNamesFromAvailableDisplaysLocked() { boolean changed = false; for (int i = 0; i < mRememberedDisplays.length; i++) { WifiDisplay rememberedDisplay = mRememberedDisplays[i]; WifiDisplay availableDisplay = findAvailableDisplayLocked( rememberedDisplay.getDeviceAddress()); if (availableDisplay != null && !rememberedDisplay.equals(availableDisplay)) { mRememberedDisplays[i] = availableDisplay; changed |= mPersistentDataStore.rememberWifiDisplay(availableDisplay); } } if (changed) { mPersistentDataStore.saveIfNeeded(); } }如果扫描到的设备列表中有wifi display设备的名字或者别名发生了变化,就会调用到PersistentDataStore.saveIfNeeded方法把数据写到/data/system/display-manager-state.xml中。
private void updateDisplaysLocked() { List<WifiDisplay> displays = new ArrayList<WifiDisplay>( mAvailableDisplays.length + mRememberedDisplays.length); boolean[] remembered = new boolean[mAvailableDisplays.length]; for (WifiDisplay d : mRememberedDisplays) { boolean available = false; for (int i = 0; i < mAvailableDisplays.length; i++) { if (d.equals(mAvailableDisplays[i])) { remembered[i] = available = true; break; } } if (!available) { displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(), d.getDeviceAlias(), false, false, true)); } } for (int i = 0; i < mAvailableDisplays.length; i++) { WifiDisplay d = mAvailableDisplays[i]; displays.add(new WifiDisplay(d.getDeviceAddress(), d.getDeviceName(), d.getDeviceAlias(), true, d.canConnect(), remembered[i])); } mDisplays = displays.toArray(WifiDisplay.EMPTY_ARRAY); }
static void updateWifiDisplayStatus(WifiDisplayStatus status) { WifiDisplay[] displays; WifiDisplay activeDisplay; if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { displays = status.getDisplays(); activeDisplay = status.getActiveDisplay(); } else { displays = WifiDisplay.EMPTY_ARRAY; activeDisplay = null; } String activeDisplayAddress = activeDisplay != null ? activeDisplay.getDeviceAddress() : null; // Add or update routes. for (int i = 0; i < displays.length; i++) { final WifiDisplay d = displays[i]; if (shouldShowWifiDisplay(d, activeDisplay)) { RouteInfo route = findWifiDisplayRoute(d); if (route == null) { route = makeWifiDisplayRoute(d, status); addRouteStatic(route); } else { String address = d.getDeviceAddress(); boolean disconnected = !address.equals(activeDisplayAddress) && address.equals(sStatic.mPreviousActiveWifiDisplayAddress); updateWifiDisplayRoute(route, d, status, disconnected); } if (d.equals(activeDisplay)) { selectRouteStatic(route.getSupportedTypes(), route, false); } } } // Remove stale routes. for (int i = sStatic.mRoutes.size(); i-- > 0; ) { RouteInfo route = sStatic.mRoutes.get(i); if (route.mDeviceAddress != null) { WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress); if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) { removeRouteStatic(route); } } } sStatic.mPreviousActiveWifiDisplayAddress = activeDisplayAddress; }
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) { scheduleUpdate(CHANGE_WIFI_DISPLAY_STATUS); } } };
private void update(int changes) { boolean invalidateOptions = false; // Update wifi display state. if ((changes & CHANGE_WIFI_DISPLAY_STATUS) != 0) { mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus(); // The wifi display feature state may have changed. invalidateOptions = true; } // Rebuild the routes. final PreferenceScreen preferenceScreen = getPreferenceScreen(); preferenceScreen.removeAll(); // Add all known remote display routes. final int routeCount = mRouter.getRouteCount(); for (int i = 0; i < routeCount; i++) { MediaRouter.RouteInfo route = mRouter.getRouteAt(i); if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) { preferenceScreen.addPreference(createRoutePreference(route)); } } // Additional features for wifi display routes. if (mWifiDisplayStatus != null && mWifiDisplayStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) { // Add all unpaired wifi displays. for (WifiDisplay display : mWifiDisplayStatus.getDisplays()) { if (!display.isRemembered() && display.isAvailable() && !display.equals(mWifiDisplayStatus.getActiveDisplay())) { preferenceScreen.addPreference(new UnpairedWifiDisplayPreference( getActivity(), display)); } } } }