Framework StatusBar添加(wifi,bluetooth,gps,sound,rotate)控制面板
16lz
2021-01-26
学android已经数月了,最近跳槽了一家做手机的公司,一去就是改framework层里的代码,那个纠结啊。第一个项目就是改statusbar,添加控制面板开关。
因为项目公司里任何的资源都带不出来,就用我自己的手机截图示范,跟android原生statusbar对比,源码主要以wifi为示例。
我做的项目是添加WIFI,BLUETOOTH,GPS,SOUND,自动旋转,个人感觉自动旋转是最让人纠结的,因为无法监听到状态的广播,不过可以监听数据库里的变化。我主要以WIFI项目示范,其他的四个提下我的思路,欢迎大家探讨。
修改的图片文件位置:
platform\frameworks\base\packages\SystemUI\res\drawable-hdpi
添加switch_wifi_on.png,switch_wifi_off.png,switch_ind_on.png,switch_ind_off.png,swith_bg
修改的layout文件位置:
platform\frameworks\base\packages\SystemUI\res\layout\status_bar_expanded.xml修改的string文件位置:
中文
platform\frameworks\base\packages\SystemUI\res\values-zh-rCN\strings.xml
英文
platform\frameworks\base\packages\SystemUI\res\values\strings.xml
代码文件位置:platform\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\StatusBarService.java在status_bar_expanded.xml里添加5个开关的排列,添加在最顶层的android:background="@drawable/title_bar_portrait"的这个LinearLayout的上面,那样控制面板就会显示在最顶层了,大家看下源码就知道了,下面添加的是wifi的,添加其他的开关继续在里面添加即可。<LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/switch_bg"><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/switch_wifi"><ImageView android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/switch_wifi_img"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/switch_wifi_text"/><ImageView android:layout_width="fill_parent"android:layout_height="wrap_content"android:id="@+id/switch_ind_state"/></LinearLayout></LinearLayout>
功能控制添加在StatusBarService.xml文件里:定义变量:private WifiManager mWifiManager; private IntentFilter mWifiStateFilter; LinearLayout mWifiState; ImageView mWifiImg; TextView mWifiText; ImageView mWifiInd;在private void makeStatusBarView(Context context)定义这些变量的值及要用的广播等。mWifiState=(LinearLayout)expanded.findViewById(R.id.switch_wifi); mWifiState.setOnClickListener(mWifiChangeListener); mWifiImg=(ImageView)expanded.findViewById(R.id.switch_wifi_img); mWifiText=(TextView)expanded.findViewById(R.id.switch_wifi_text); mWifiInd=(ImageView)expanded.findViewById(R.id.switch_ind_state); mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE); mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); registerReceiver(mWifiStateReceiver, mWifiStateFilter);然后在其他位置添加广播,定义的5个状态的样式及点击切换等。private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, mWifiManager.getWifiState())); } } }; private void handleWifiStateChanged(int wifiState) { switch(wifiState){ case WifiManager.WIFI_STATE_DISABLED: mWifiImg.setBackgroundResource(R.drawable.switch_wifi_off); mWifiText.setText(R.string.switch_wifi_text_off); mWifiInd.setBackgroundResource(R.drawable.switch_ind_off); break; case WifiManager.WIFI_STATE_DISABLING: mWifiImg.setBackgroundResource(R.drawable.switch_wifi_on); mWifiText.setText(R.string.switch_wifi_text_closing); mWifiInd.setBackgroundResource(R.drawable.switch_ind_on); break; case WifiManager.WIFI_STATE_ENABLED: mWifiImg.setBackgroundResource(R.drawable.switch_wifi_on); mWifiText.setText(R.string.switch_wifi_text_on); mWifiInd.setBackgroundResource(R.drawable.switch_ind_on); break; case WifiManager.WIFI_STATE_ENABLING: mWifiImg.setBackgroundResource(R.drawable.switch_wifi_off); mWifiText.setText(R.string.switch_wifi_text_opening); mWifiInd.setBackgroundResource(R.drawable.switch_ind_off); break; case WifiManager.WIFI_STATE_UNKNOWN: mWifiImg.setBackgroundResource(R.drawable.switch_wifi_off); mWifiText.setText(R.string.switch_wifi_text_off); mWifiInd.setBackgroundResource(R.drawable.switch_wifi_off); break; } } private View.OnClickListener mWifiChangeListener = new View.OnClickListener() { public void onClick(View v) { if(mWifiManager.getWifiState()==WifiManager.WIFI_STATE_DISABLED){ mWifiManager.setWifiEnabled(true); handleWifiStateChanged(WifiManager.WIFI_STATE_ENABLED); }else{ mWifiManager.setWifiEnabled(false); handleWifiStateChanged(WifiManager.WIFI_STATE_DISABLED); } } };在strings.xml文件里添加<string name="switch_wifi_text_on">wifi</string><string name="switch_wifi_text_off">wifi</string><string name="switch_wifi_text_opening">opening</string><string name="switch_wifi_text_closing">closing</string>
就这样一个wifi的控制开关就完成了。因为是在家里写的,所以完整的代码无法打出来,就当给大家点提示吧。wifi的源文件可以参考:platform\packages\apps\Settings\src\com\android\settings\wifi在widget里已经有一个范例了,大家可以参考里面的广播。platform\packages\apps\Settings\src\com\android\settings\widget\SettingsAppWidgetProvider.javapublic void onReceive(Context context, Intent intent) { super.onReceive(context, intent); String action = intent.getAction(); if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { sWifiState.onActualStateChange(context, intent); } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { sBluetoothState.onActualStateChange(context, intent); } else if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(action)) { sGpsState.onActualStateChange(context, intent); } else if (SyncStorageEngine.SYNC_CONNECTION_SETTING_CHANGED_INTENT.getAction() .equals(action)) { sSyncState.onActualStateChange(context, intent); } else if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) { Uri data = intent.getData(); int buttonId = Integer.parseInt(data.getSchemeSpecificPart()); if (buttonId == BUTTON_WIFI) { sWifiState.toggleState(context); } else if (buttonId == BUTTON_BRIGHTNESS) { toggleBrightness(context); } else if (buttonId == BUTTON_SYNC) { sSyncState.toggleState(context); } else if (buttonId == BUTTON_GPS) { sGpsState.toggleState(context); } else if (buttonId == BUTTON_BLUETOOTH) { sBluetoothState.toggleState(context); } } else { // Don't fall-through to updating the widget. The Intent // was something unrelated or that our super class took // care of. return; } // State changes fall through updateWidget(context); }bluetooth也是一样的注册广播,监听变化。BluetoothAdapter,主要是这个类的相关应用。private void handleStateChanged(int state) { switch (state) { case BluetoothAdapter.STATE_TURNING_ON: mCheckBox.setSummary(R.string.wifi_starting); mCheckBox.setEnabled(false); break; case BluetoothAdapter.STATE_ON: mCheckBox.setChecked(true); mCheckBox.setSummary(null); mCheckBox.setEnabled(true); break; case BluetoothAdapter.STATE_TURNING_OFF: mCheckBox.setSummary(R.string.wifi_stopping); mCheckBox.setEnabled(false); break; case BluetoothAdapter.STATE_OFF: mCheckBox.setChecked(false); mCheckBox.setSummary(mOriginalSummary); mCheckBox.setEnabled(true); break; default: mCheckBox.setChecked(false); mCheckBox.setSummary(R.string.wifi_error); mCheckBox.setEnabled(true); } }private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { handleBluetoothStateChanged(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, mBluetoothAdapter.getState());); } };GPS则是监听数据库里的开关变化参考写法:platform\packages\apps\Settings\src\com\android\settings\widget\SettingsAppWidgetProvider.javaprivate static final class GpsStateTracker extends StateTracker { public int getButtonId() { return R.id.img_gps; } public int getIndicatorId() { return R.id.ind_gps; } public int getButtonImageId(boolean on) { return on ? R.drawable.ic_appwidget_settings_gps_on : R.drawable.ic_appwidget_settings_gps_off; } @Override public int getActualState(Context context) { ContentResolver resolver = context.getContentResolver(); boolean on = Settings.Secure.isLocationProviderEnabled( resolver, LocationManager.GPS_PROVIDER); return on ? STATE_ENABLED : STATE_DISABLED; } @Override public void onActualStateChange(Context context, Intent unused) { // Note: the broadcast location providers changed intent // doesn't include an extras bundles saying what the new value is. setCurrentState(context, getActualState(context)); } @Override public void requestStateChange(final Context context, final boolean desiredState) { final ContentResolver resolver = context.getContentResolver(); new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... args) { Settings.Secure.setLocationProviderEnabled( resolver, LocationManager.GPS_PROVIDER, desiredState); return desiredState; } @Override protected void onPostExecute(Boolean result) { setCurrentState( context, result ? STATE_ENABLED : STATE_DISABLED); updateWidget(context); } }.execute(); } }sound则是参考platform\packages\apps\Settings\src\com\android\settings\SoundSettings.javaprivate BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { updateState(false); } } };IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); registerReceiver(mReceiver, filter);自动选择则是参考:platform\packages\apps\Settings\src\com\android\settings\DisplaySettings.javapublic boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if (preference == mAccelerometer) {
//设置数据库里自动选择的开关,1为开,0为关Settings.System.putInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, mAccelerometer.isChecked() ? 1 : 0); } return true; }写一个类继承于ContentResolver,用于监听数据库里的变化,然后即可。
以上代码皆可在android源码里找到相关资源,欢迎大家互相讨论。
更多相关文章
- Android(安卓)开发者 for Flutter (2)如何布局? XML layout 文件跑
- android android 在list view中插入一条广告
- Android(安卓)引导页动态添加圆点指示器
- android 上面一个listview下面一个button,让button一直处于listv
- Android5.0 下拉通知栏快捷开关的添加(必看)
- Android(安卓)网络状态监听那些事
- Android中Dialog对话框的调用及监听
- Android(安卓)使用AsyncTask 后监听异步加载完毕的动作-(by terry
- Android实现https网络通信之添加指定信任证书/信任所有证书