Android 8.1プラットフォームSystemUI仮想ナビゲーションキーロードプロセス解析
25543 ワード
需要
MTK 8163 8.1プラットフォームのカスタマイズナビゲーションバー部分に基づいて、左側で音量を増やして減らし、右側で音量を増やして加え、カスタマイズする必要がある手順は次の文章を参照してください.
構想
需要が始まる前に、SystemUI Navigationモジュールのコードフローを研究しなければなりません!!!ネット上のcopyに直接行かないでください.他の人が変更した需要コードは、ブラインドで変更すると問題が発生しやすいですが、解決できません.ネット上には古いプラットフォーム(8.0-)のSystem UIを説明するナビゲーションバーモジュールのブログがあり、自分で検索します.8.0 System UIに対してやはり多くの細部の上の変更をして、コードの変更の体現の上で比較的に多くて、しかし全体の基本的な流れは変わっていません.
ソースコードを読むと、コードの詳細を気にしないでください.例えば、私はこの需要をカスタマイズして、ナビゲーションバーの戻り(back)、デスクトップ(home)、最近のタスク(recent)の中の1つの機能とコードの流れについて、例えばrecenというviewがどの方法でどの方法を調整して最終的にロードしたのか、ロードしたキーコードがどこにあるのか、クリックイベントがどのように生成されるのか、中の具体的な論理判断を気にしないなど、大体知っています.
コードフロー
1.SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java;
ステータスバー入口から見ます.
2.SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java;
createNavigationBarの方法に入って、主にNavigationBarFragmentで管理することを発見した.
3.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFragment.java;
NavigationBarFragmentのcreateメソッドを見て、やっと分かったのは、WindowManagerがaddViewに行ってナビゲーションバーのレイアウトをし、最終的にfragmentのonCreateViewがロードしたレイアウトをaddしたことだ.(実はSystemUIのすべてのモジュールはWindowManagerでViewをロードしています.)
4.SystemUI\res\layoutavigation_bar_window.xml;
WindowManagerがロードしたこのviewのレイアウトを見てみましょう:navigation_bar_window.xml,ルートレイアウトがカスタムviewクラスNavigationBarFrameであることが分かった.(実はSystemUIや他のシステムアプリケーション、例えばLauncherは、このようなカスタムviewの方式であり、多くの論理処理もカスタムviewにあり、無視できない)
5.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFrame.java;
NavigationBarFrameクラスに入ります.発見クラスは私たちの予想ではなく、FrameLayoutであり、DeadZone機能下のtouchイベントに手を出した.
6.NavigationBarFragmentのライフサイクルを見てみましょう.onCreateView()では、ナビゲーションバーの本物のrootView.
7.SystemUI\res\layoutavigation_bar.xml;
ナビゲーションバーの真のルートレイアウトに入る:navigation_bar.xml、いいでしょうまたカスタムviewで、NavigationBarViewとNavigationBarInflaterViewはよく研究しなければなりません.
8.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarInflaterView.java;FrameLayoutから受け継ぐ
まず構造方法を見てみましょう.xmlレイアウトをロードするにはまず初期化が行われますから.
さらにonFinishInflate()メソッドを見ると、これはviewのライフサイクルであり、各viewがinflateされた後にコールバックされます.
inflateLayout():中のnewLayoutパラメータはとても重要です!!!前の方法でgetDefaultLayout()を見て、彼はxmlで死んだ文字列をreturnしました.さらにinflateLayoutメソッドを見て、xmlに配置された文字列を解析的に分割し、inflateButtonsメソッドに伝えた.
さらにinflateButtons()メソッドを見て、inflateButtonをループロードします.
createView()メソッドを見てみましょう.ホームボタンを例にとると、ホームのbuttonがロードされていますが、実はR.layoutがロードされています.ホームのlayoutレイアウト
9.SystemUI\src\com\android\systemui\statusbar\policy\KeyButtonView.JAvaはまずKeyButtonViewの構造方法を見てみましょう.xmlのsystemui:keyCode=「3」の方法はここで取得しました.さらにTouchイベントを見ると、sendEvent()メソッドにより、backなどのviewのクリックtouchイベントは自分で処理するのではなく、システムによって実体ボタン(keycode)の形で処理されていることがわかる.
もちろんKeyButtonViewクラスでは,長押をサポートするbutton,ボタンの音なども扱っているが,ここでは無視する.
これで、ナビゲーションバーのボタンイベントを整理しました.
10.画像を設定するiconはいったいどこにあるのかという質問も残っています.私たちがずっと読んでいたのはNavigationBarInflaterViewで、レイアウトによって私たちはもう一つのクラスを見ていません.NavigationBarView.java
SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java;
NavigationBarViewクラスに入り、構造方法を見つけます.
11.第10から分かるように、recentを例にとると、初期化時にmRecentIconのリソースが得られ、誰がmRecentIconを呼び出したかを見れば分かる、すなわち呼び出しの流れを反転して見ることができる.
updateRecentsIconこの方法はrecentピクチャのリソースを設定し、誰がupdateRecentsIconメソッドを呼び出したかを見てみましょう:onConfigurationChanged画面が回転するとリソースピクチャが再設定されます
reorient()はsetNavigationIconHints()メソッドも呼び出します.
さらに上に進むと、最終的にNavigationBarFragmentのonConfigurationChanged()メソッドとNavigationBarViewのonAttachedToWindow()メソッドとonSizeChanged()メソッドに遡る.つまり、NavigationBarViewナビゲーションバーというレイアウトがロードされたときに画像リソースが設定され、長さが変更され、画面の回転が再設定される可能性があります
これで、SystemUIの仮想ナビゲーションバーモジュールコード処理が終了します.
まとめ windowプロパティの親view を作成解析xml内のconfigの構成、addViewに必要なicon、または置換順序 を読み取る. srcピクチャリソースコードにより明るい色と暗い色を設定 touchイベントはkeycode方式でシステム処理 に渡す.
次のセクションでは、音量の増減のカスタマイズ手順について説明します.
転載先:https://juejin.im/post/5ad9a077f265da0b767d0669
MTK 8163 8.1プラットフォームのカスタマイズナビゲーションバー部分に基づいて、左側で音量を増やして減らし、右側で音量を増やして加え、カスタマイズする必要がある手順は次の文章を参照してください.
構想
需要が始まる前に、SystemUI Navigationモジュールのコードフローを研究しなければなりません!!!ネット上のcopyに直接行かないでください.他の人が変更した需要コードは、ブラインドで変更すると問題が発生しやすいですが、解決できません.ネット上には古いプラットフォーム(8.0-)のSystem UIを説明するナビゲーションバーモジュールのブログがあり、自分で検索します.8.0 System UIに対してやはり多くの細部の上の変更をして、コードの変更の体現の上で比較的に多くて、しかし全体の基本的な流れは変わっていません.
ソースコードを読むと、コードの詳細を気にしないでください.例えば、私はこの需要をカスタマイズして、ナビゲーションバーの戻り(back)、デスクトップ(home)、最近のタスク(recent)の中の1つの機能とコードの流れについて、例えばrecenというviewがどの方法でどの方法を調整して最終的にロードしたのか、ロードしたキーコードがどこにあるのか、クリックイベントがどのように生成されるのか、中の具体的な論理判断を気にしないなど、大体知っています.
コードフロー
1.SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java;
ステータスバー入口から見ます.
protected void makeStatusBarView() {
final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
...
...
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
createNavigationBar();//
}
} catch (RemoteException ex) {
}
}
2.SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java;
createNavigationBarの方法に入って、主にNavigationBarFragmentで管理することを発見した.
protected void createNavigationBar() {
mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
mNavigationBar = (NavigationBarFragment) fragment;
if (mLightBarController != null) {
mNavigationBar.setLightBarController(mLightBarController);
}
mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
});
}
3.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFragment.java;
NavigationBarFragmentのcreateメソッドを見て、やっと分かったのは、WindowManagerがaddViewに行ってナビゲーションバーのレイアウトをし、最終的にfragmentのonCreateViewがロードしたレイアウトをaddしたことだ.(実はSystemUIのすべてのモジュールはWindowManagerでViewをロードしています.)
public static View create(Context context, FragmentListener listener) {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.setTitle("NavigationBar");
lp.windowAnimations = 0;
View navigationBarView = LayoutInflater.from(context).inflate(
R.layout.navigation_bar_window, null);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
if (navigationBarView == null) return null;
context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
NavigationBarFragment fragment = new NavigationBarFragment();
fragmentHost.getFragmentManager().beginTransaction()
.replace(R.id.navigation_bar_frame, fragment, TAG) // !fragment onCreateView add Window view 。
.commit();
fragmentHost.addTagListener(TAG, listener);
return navigationBarView;
}
}
4.SystemUI\res\layoutavigation_bar_window.xml;
WindowManagerがロードしたこのviewのレイアウトを見てみましょう:navigation_bar_window.xml,ルートレイアウトがカスタムviewクラスNavigationBarFrameであることが分かった.(実はSystemUIや他のシステムアプリケーション、例えばLauncherは、このようなカスタムviewの方式であり、多くの論理処理もカスタムviewにあり、無視できない)
"http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_bar_frame"
android:layout_height="match_parent"
android:layout_width="match_parent">
5.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFrame.java;
NavigationBarFrameクラスに入ります.発見クラスは私たちの予想ではなく、FrameLayoutであり、DeadZone機能下のtouchイベントに手を出した.
6.NavigationBarFragmentのライフサイクルを見てみましょう.onCreateView()では、ナビゲーションバーの本物のrootView.
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.navigation_bar, container, false);
}
7.SystemUI\res\layoutavigation_bar.xml;
ナビゲーションバーの真のルートレイアウトに入る:navigation_bar.xml、いいでしょうまたカスタムviewで、NavigationBarViewとNavigationBarInflaterViewはよく研究しなければなりません.
"http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="@drawable/system_bar_background">
"@+id/navigation_inflater"
android:layout_width="match_parent"
android:layout_height="match_parent" />
8.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarInflaterView.java;FrameLayoutから受け継ぐ
まず構造方法を見てみましょう.xmlレイアウトをロードするにはまず初期化が行われますから.
public NavigationBarInflaterView(Context context, AttributeSet attrs) {
super(context, attrs);
createInflaters();// view( back home or recent)
Display display = ((WindowManager)
context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Mode displayMode = display.getMode();
isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight();
}
private void inflateChildren() {
removeAllViews();
mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false);
mRot0.setId(R.id.rot0);
addView(mRot0);
mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this,
false);
mRot90.setId(R.id.rot90);
addView(mRot90);
updateAlternativeOrder();
}
さらにonFinishInflate()メソッドを見ると、これはviewのライフサイクルであり、各viewがinflateされた後にコールバックされます.
@Override
protected void onFinishInflate() {
super.onFinishInflate();
inflateChildren();//
clearViews();//
inflateLayout(getDefaultLayout());// : back.home.recent layout
}
inflateLayout():中のnewLayoutパラメータはとても重要です!!!前の方法でgetDefaultLayout()を見て、彼はxmlで死んだ文字列をreturnしました.さらにinflateLayoutメソッドを見て、xmlに配置された文字列を解析的に分割し、inflateButtonsメソッドに伝えた.
protected void inflateLayout(String newLayout) {
mCurrentLayout = newLayout;
if (newLayout == null) {
newLayout = getDefaultLayout();
}
String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);// “;” 3
String[] start = sets[0].split(BUTTON_SEPARATOR);// “,” , left[.5W] back[1WC]
String[] center = sets[1].split(BUTTON_SEPARATOR);// home
String[] end = sets[2].split(BUTTON_SEPARATOR);// recent[1WC] right[.5W]
// Inflate these in start to end order or accessibility traversal will be messed up.
inflateButtons(start, mRot0.findViewById(R.id.ends_group), isRot0Landscape, true);
inflateButtons(start, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, true);
inflateButtons(center, mRot0.findViewById(R.id.center_group), isRot0Landscape, false);
inflateButtons(center, mRot90.findViewById(R.id.center_group), !isRot0Landscape, false);
addGravitySpacer(mRot0.findViewById(R.id.ends_group));
addGravitySpacer(mRot90.findViewById(R.id.ends_group));
inflateButtons(end, mRot0.findViewById(R.id.ends_group), isRot0Landscape, false);
inflateButtons(end, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, false);
}
protected String getDefaultLayout() {
return mContext.getString(R.string.config_navBarLayout);
}
//SystemUI\res\values\config.xml
"config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]
さらにinflateButtons()メソッドを見て、inflateButtonをループロードします.
private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape,
boolean start) {
for (int i = 0; i < buttons.length; i++) {
inflateButton(buttons[i], parent, landscape, start);
}
}
@Nullable
protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
boolean start) {
LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
View v = createView(buttonSpec, parent, inflater);// view
if (v == null) return null;
v = applySize(v, buttonSpec, landscape, start);
parent.addView(v);//addView
addToDispatchers(v);
View lastView = landscape ? mLastLandscape : mLastPortrait;
View accessibilityView = v;
if (v instanceof ReverseFrameLayout) {
accessibilityView = ((ReverseFrameLayout) v).getChildAt(0);
}
if (lastView != null) {
accessibilityView.setAccessibilityTraversalAfter(lastView.getId());
}
if (landscape) {
mLastLandscape = accessibilityView;
} else {
mLastPortrait = accessibilityView;
}
return v;
}
createView()メソッドを見てみましょう.ホームボタンを例にとると、ホームのbuttonがロードされていますが、実はR.layoutがロードされています.ホームのlayoutレイアウト
private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
View v = null;
...
...
if (HOME.equals(button)) {
v = inflater.inflate(R.layout.home, parent, false);
} else if (BACK.equals(button)) {
v = inflater.inflate(R.layout.back, parent, false);
} else if (RECENT.equals(button)) {
v = inflater.inflate(R.layout.recent_apps, parent, false);
} else if (MENU_IME.equals(button)) {
v = inflater.inflate(R.layout.menu_ime, parent, false);
} else if (NAVSPACE.equals(button)) {
v = inflater.inflate(R.layout.nav_key_space, parent, false);
} else if (CLIPBOARD.equals(button)) {
v = inflater.inflate(R.layout.clipboard, parent, false);
}
...
...
return v;
}
//SystemUI\res\layout\home.xml
// src home icon,
// view:KeyButtonView
"http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/home"
android:layout_width="@dimen/navigation_key_width"// dimens.xml navigation_key_width
android:layout_height="match_parent"
android:layout_weight="0"
systemui:keyCode="3"//systemui
android:scaleType="fitCenter"
android:contentDescription="@string/accessibility_home"
android:paddingTop="@dimen/home_padding"
android:paddingBottom="@dimen/home_padding"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
9.SystemUI\src\com\android\systemui\statusbar\policy\KeyButtonView.JAvaはまずKeyButtonViewの構造方法を見てみましょう.xmlのsystemui:keyCode=「3」の方法はここで取得しました.さらにTouchイベントを見ると、sendEvent()メソッドにより、backなどのviewのクリックtouchイベントは自分で処理するのではなく、システムによって実体ボタン(keycode)の形で処理されていることがわかる.
もちろんKeyButtonViewクラスでは,長押をサポートするbutton,ボタンの音なども扱っているが,ここでは無視する.
これで、ナビゲーションバーのボタンイベントを整理しました.
public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
defStyle, 0);
mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
TypedValue value = new TypedValue();
if (a.getValue(R.styleable.KeyButtonView_android_contentDescription, value)) {
mContentDescriptionRes = value.resourceId;
}
a.recycle();
setClickable(true);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRipple = new KeyButtonRipple(context, this);
setBackground(mRipple);
}
...
...
public boolean onTouchEvent(MotionEvent ev) {
...
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownTime = SystemClock.uptimeMillis();
mLongClicked = false;
setPressed(true);
if (mCode != 0) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);//
} else {
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
playSoundEffect(SoundEffectConstants.CLICK);
removeCallbacks(mCheckLongPress);
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
break;
...
...
}
return true;
}
void sendEvent(int action, int flags, long when) {
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(mCode)
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
// mCode new KeyEvent , injectInputEvent 。
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
InputManager.getInstance().injectInputEvent(ev,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
10.画像を設定するiconはいったいどこにあるのかという質問も残っています.私たちがずっと読んでいたのはNavigationBarInflaterViewで、レイアウトによって私たちはもう一つのクラスを見ていません.NavigationBarView.java
SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java;
NavigationBarViewクラスに入り、構造方法を見つけます.
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mDisplay = ((WindowManager) context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
...
...
updateIcons(context, Configuration.EMPTY, mConfiguration);//
mBarTransitions = new NavigationBarTransitions(this);
//mButtonDispatchers home back recent view , child,NavigationBarInflaterView
mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
mButtonDispatchers.put(R.id.accessibility_button,
new ButtonDispatcher(R.id.accessibility_button));
}
private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
...
iconLight = mNavBarPlugin.getHomeImage(
ctx.getDrawable(R.drawable.ic_sysbar_home));
iconDark = mNavBarPlugin.getHomeImage(
ctx.getDrawable(R.drawable.ic_sysbar_home_dark));
//mHomeDefaultIcon = getDrawable(ctx,
// R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
mHomeDefaultIcon = getDrawable(iconLight,iconDark);
// icon
iconLight = mNavBarPlugin.getRecentImage(
ctx.getDrawable(R.drawable.ic_sysbar_recent));
// icon
iconDark = mNavBarPlugin.getRecentImage(
ctx.getDrawable(R.drawable.ic_sysbar_recent_dark));
//mRecentIcon = getDrawable(ctx,
// R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
mRecentIcon = getDrawable(iconLight,iconDark);
mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu,
R.drawable.ic_sysbar_menu_dark);
...
...
}
11.第10から分かるように、recentを例にとると、初期化時にmRecentIconのリソースが得られ、誰がmRecentIconを呼び出したかを見れば分かる、すなわち呼び出しの流れを反転して見ることができる.
private void updateRecentsIcon() {
getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
mBarTransitions.reapplyDarkIntensity();
}
updateRecentsIconこの方法はrecentピクチャのリソースを設定し、誰がupdateRecentsIconメソッドを呼び出したかを見てみましょう:onConfigurationChanged画面が回転するとリソースピクチャが再設定されます
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
boolean uiCarModeChanged = updateCarMode(newConfig);
updateTaskSwitchHelper();
updateIcons(getContext(), mConfiguration, newConfig);
updateRecentsIcon();
if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi
|| mConfiguration.getLayoutDirection() != newConfig.getLayoutDirection()) {
// If car mode or density changes, we need to reset the icons.
setNavigationIconHints(mNavigationIconHints, true);
}
mConfiguration.updateFrom(newConfig);
}
public void setNavigationIconHints(int hints, boolean force) {
...
...
mNavigationIconHints = hints;
// We have to replace or restore the back and home button icons when exiting or entering
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
KeyButtonDrawable backIcon = (backAlt)
? getBackIconWithAlt(mUseCarModeUi, mVertical)
: getBackIcon(mUseCarModeUi, mVertical);
getBackButton().setImageDrawable(backIcon);
updateRecentsIcon();
...
...
}
reorient()はsetNavigationIconHints()メソッドも呼び出します.
public void reorient() {
updateCurrentView();
...
setNavigationIconHints(mNavigationIconHints, true);
getHomeButton().setVertical(mVertical);
}
さらに上に進むと、最終的にNavigationBarFragmentのonConfigurationChanged()メソッドとNavigationBarViewのonAttachedToWindow()メソッドとonSizeChanged()メソッドに遡る.つまり、NavigationBarViewナビゲーションバーというレイアウトがロードされたときに画像リソースが設定され、長さが変更され、画面の回転が再設定される可能性があります
これで、SystemUIの仮想ナビゲーションバーモジュールコード処理が終了します.
まとめ
次のセクションでは、音量の増減のカスタマイズ手順について説明します.
転載先:https://juejin.im/post/5ad9a077f265da0b767d0669