当前位置:   article > 正文

导航栏的介绍_navigationbarinflaterview 添加布局

navigationbarinflaterview 添加布局

一、导航栏的创建:

         PhoneStatusBar -->makeStatusBarView();         

  1. try {
  2. boolean showNav = mWindowManagerService.hasNavigationBar();//向wms询问是否需要导航栏
  3. //if (DEBUG)
  4. Log.v(TAG, "hasNavigationBar=" + showNav);
  5. if (showNav) {
  6. createNavigationBarView(context);//创建导航栏
  7. }
  8. } catch (RemoteException ex) {
  9. // no window manager? good luck with that

 

mWindowManagerService.hasNavigationBar向framework 下面的config.xml中获取   com.android.internal.R.bool.config_showNavigationBar。

     createNavigationBarView(context):

             

  1. protected void createNavigationBarView(Context context) {
  2. inflateNavigationBarView(context);//加载导航栏布局文件
  3. mNavigationBarView.setDisabledFlags(mDisabled1);//禁用某些功能switches[0]
  4. mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));//添加控制按键。
  5. mNavigationBarView.setOnVerticalChangedListener(
  6. new NavigationBarView.OnVerticalChangedListener() {
  7. @Override
  8. public void onVerticalChanged(boolean isVertical) {
  9. if (mAssistManager != null) {
  10. mAssistManager.onConfigurationChanged();
  11. }
  12. mNotificationPanel.setQsScrimEnabled(!isVertical);
  13. }
  14. });
  15. mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
  16. @Override
  17. public boolean onTouch(View v, MotionEvent event) {
  18. checkUserAutohide(v, event);
  19. return false;
  20. }});
  21. }

至此导航栏的UI界面是创建完成但是功能还未全部加载完成,比如按近期列表无效,所以还需要在PhoneStatusBar ->start()中加载addNavigationBar()。

           

  1. protected void addNavigationBar() {
  2. if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
  3. if (mNavigationBarView == null) return;
  4. prepareNavigationBarView();
  5. mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());//把这个添加到window窗口
  6. }
  1.  private void prepareNavigationBarView() {
  2.         mNavigationBarView.reorient();//方向的初始化
  3.         ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
  4. //近期列表的监听
  5.         recentsButton.setOnClickListener(mRecentsClickListener);
  6.         recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
  7.         recentsButton.setLongClickable(true);
  8.         recentsButton.setOnLongClickListener(mRecentsLongClickListener);
  9.         ButtonDispatcher backButton = mNavigationBarView.getBackButton();
  10.         backButton.setLongClickable(true);
  11.         backButton.setOnLongClickListener(mLongPressBackListener);
  12.    
  13.         ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
  14.         homeButton.setOnTouchListener(mHomeActionListener);
  15.         homeButton.setOnLongClickListener(mLongPressHomeListener);
  16.         /// M: BMW  restore button @{
  17.         if (MultiWindowManager.isSupported()) {
  18.             ButtonDispatcher restoreButton = mNavigationBarView.getRestoreButton();
  19.             restoreButton.setOnClickListener(mRestoreClickListener);
  20.         }
  21.         /// @}
  22.         mAssistManager.onConfigurationChanged();
  23.     }
       在上述的代码 recentsButton 、backButton、homeButton分别对应的是导航栏中的近期列表、返回键、Home键。如果继续追溯它们所添加的监听,并未发现back 和home的功能实现,只有近期列表的功能实现。那back 和home的功能实现是在哪里呢?后面会讲到。


二、导航栏的UI界面显示:

        导航栏的创建     

  1. protected void inflateNavigationBarView(Context context) {
  2. mNavigationBarView = (NavigationBarView) View.inflate(
  3. context, R.layout.navigation_bar, null);
  4. }


    navigation_bar.xml: 

  1. <com.android.systemui.statusbar.phone.NavigationBarView
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:systemui="http://schemas.android.com/apk/res-auto"
  4. android:layout_height="match_parent"
  5. android:layout_width="match_parent"
  6. android:background="@drawable/system_bar_background">
  7. <com.android.systemui.statusbar.phone.NavigationBarInflaterView
  8. android:id="@+id/navigation_inflater"
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent" />
  11. </com.android.systemui.statusbar.phone.NavigationBarView>

    注: @drawable/system_bar_background  导航栏的背景控制

  NavigationBarInflaterView

              

  1. public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
  2. private static final String TAG = "NavBarInflater";
  3. public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
  4. public static final String MENU_IME = "menu_ime";
  5. public static final String BACK = "back";
  6. public static final String HOME = "home";
  7. public static final String RECENT = "recent";
  8. public static final String NAVSPACE = "space";
  9. public static final String CLIPBOARD = "clipboard";
  10. public static final String KEY = "key";
  11. /// M: BMW @{
  12. public static final String RESTORE = "restore";
  13. /// @}
  14. public static final String GRAVITY_SEPARATOR = ";";
  15. public static final String BUTTON_SEPARATOR = ",";
  16. public static final String SIZE_MOD_START = "[";
  17. public static final String SIZE_MOD_END = "]";
  18. public static final String KEY_CODE_START = "(";
  19. public static final String KEY_IMAGE_DELIM = ":";
  20. public static final String KEY_CODE_END = ")";
  21. protected LayoutInflater mLayoutInflater;
  22. protected LayoutInflater mLandscapeInflater;
  23. private int mDensity;
  24. protected FrameLayout mRot0;
  25. protected FrameLayout mRot90;
  26. private SparseArray<ButtonDispatcher> mButtonDispatchers;
  27. private String mCurrentLayout;
  28. private View mLastRot0;
  29. private View mLastRot90;
  30. public NavigationBarInflaterView(Context context, AttributeSet attrs) {
  31. super(context, attrs);
  32. mDensity = context.getResources().getConfiguration().densityDpi;//dpi值
  33. createInflaters();
  34. }
  35. private void createInflaters() {
  36. mLayoutInflater = LayoutInflater.from(mContext);
  37. Configuration landscape = new Configuration();
  38. landscape.setTo(mContext.getResources().getConfiguration());
  39. landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;//初始化方法是横向
  40. mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape));
  41. }
  42. @Override
  43. protected void onConfigurationChanged(Configuration newConfig) {
  44. super.onConfigurationChanged(newConfig);
  45. if (mDensity != newConfig.densityDpi) {
  46. mDensity = newConfig.densityDpi;
  47. createInflaters();
  48. inflateChildren();
  49. clearViews();
  50. inflateLayout(mCurrentLayout);
  51. }
  52. }
  53. @Override
  54. protected void onFinishInflate() {
  55. super.onFinishInflate();
  56. inflateChildren();
  57. clearViews();
  58. inflateLayout(getDefaultLayout());
  59. }
  60. private void inflateChildren() {
  61. removeAllViews();//移除此group上面的所有view
  62. //加载O度和90度布局
  63. mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false);
  64. mRot0.setId(R.id.rot0);
  65. addView(mRot0);
  66. mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this,
  67. false);
  68. mRot90.setId(R.id.rot90);
  69. addView(mRot90);
  70. if (getParent() instanceof NavigationBarView) {
  71. ((NavigationBarView) getParent()).updateRotatedViews();
  72. }
  73. }
  74. protected String getDefaultLayout() {
  75. /// M: BMW @{
  76. if (MultiWindowManager.isSupported()) {
  77. return mContext.getString(R.string.config_navBarLayout_float);
  78. }
  79. /// @}
  80. return mContext.getString(R.string.config_navBarLayout);
  81. }
  82. @Override
  83. protected void onAttachedToWindow() {
  84. super.onAttachedToWindow();
  85. TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
  86. }
  87. @Override
  88. protected void onDetachedFromWindow() {
  89. TunerService.get(getContext()).removeTunable(this);
  90. super.onDetachedFromWindow();
  91. }
  92. @Override
  93. public void onTuningChanged(String key, String newValue) {
  94. if (NAV_BAR_VIEWS.equals(key)) {
  95. if (!Objects.equals(mCurrentLayout, newValue)) {
  96. clearViews();
  97. inflateLayout(newValue);
  98. }
  99. }
  100. }
  101. public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDisatchers) {
  102. mButtonDispatchers = buttonDisatchers;
  103. for (int i = 0; i < buttonDisatchers.size(); i++) {
  104. initiallyFill(buttonDisatchers.valueAt(i));
  105. }
  106. }
  107. private void initiallyFill(ButtonDispatcher buttonDispatcher) {
  108. addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.ends_group));
  109. addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group));
  110. addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.ends_group));
  111. addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.center_group));
  112. }
  113. private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) {
  114. for (int i = 0; i < parent.getChildCount(); i++) {
  115. // Need to manually search for each id, just in case each group has more than one
  116. // of a single id. It probably mostly a waste of time, but shouldn't take long
  117. // and will only happen once.
  118. if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) {
  119. buttonDispatcher.addView(parent.getChildAt(i));
  120. } else if (parent.getChildAt(i) instanceof ViewGroup) {
  121. addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i));
  122. }
  123. }
  124. }
  125. protected void inflateLayout(String newLayout) {
  126. mCurrentLayout = newLayout;
  127. if (newLayout == null) {
  128. newLayout = getDefaultLayout();
  129. }
  130. String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
  131. String[] start = sets[0].split(BUTTON_SEPARATOR);
  132. String[] center = sets[1].split(BUTTON_SEPARATOR);
  133. String[] end = sets[2].split(BUTTON_SEPARATOR);
  134. // Inflate these in start to end order or accessibility traversal will be messed up.
  135. inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
  136. inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
  137. inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), false);
  138. inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), true);
  139. addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
  140. addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
  141. inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
  142. inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
  143. }
  144. private void addGravitySpacer(LinearLayout layout) {
  145. layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
  146. }
  147. private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape) {
  148. for (int i = 0; i < buttons.length; i++) {
  149. inflateButton(buttons[i], parent, landscape, i);
  150. }
  151. }
  152. private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
  153. if (layoutParams instanceof LinearLayout.LayoutParams) {
  154. return new LinearLayout.LayoutParams(layoutParams.width, layoutParams.height,
  155. ((LinearLayout.LayoutParams) layoutParams).weight);
  156. }
  157. return new LayoutParams(layoutParams.width, layoutParams.height);
  158. }
  159. @Nullable
  160. protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
  161. int indexInParent) {
  162. LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
  163. float size = extractSize(buttonSpec);
  164. String button = extractButton(buttonSpec);
  165. View v = null;
  166. if (HOME.equals(button)) {
  167. v = inflater.inflate(R.layout.home, parent, false);
  168. if (landscape && isSw600Dp()) {
  169. setupLandButton(v);
  170. }
  171. } else if (BACK.equals(button)) {
  172. v = inflater.inflate(R.layout.back, parent, false);
  173. if (landscape && isSw600Dp()) {
  174. setupLandButton(v);
  175. }
  176. } else if (RECENT.equals(button)) {
  177. v = inflater.inflate(R.layout.recent_apps, parent, false);
  178. if (landscape && isSw600Dp()) {
  179. setupLandButton(v);
  180. }
  181. } else if (MENU_IME.equals(button)) {
  182. v = inflater.inflate(R.layout.menu_ime, parent, false);
  183. } else if (NAVSPACE.equals(button)) {
  184. v = inflater.inflate(R.layout.nav_key_space, parent, false);
  185. /// M: BMW @{
  186. if (MultiWindowManager.isSupported() && landscape && isSw600Dp()) {
  187. setupLandButton(v);
  188. }
  189. /// @}
  190. } else if (CLIPBOARD.equals(button)) {
  191. v = inflater.inflate(R.layout.clipboard, parent, false);
  192. /// M: BMW @{
  193. } else if (MultiWindowManager.isSupported() && RESTORE.equals(button)) {
  194. v = inflater.inflate(R.layout.restore, parent, false);
  195. if (landscape && isSw600Dp()) {
  196. setupLandButton(v);
  197. }
  198. /// @}
  199. } else if (button.startsWith(KEY)) {
  200. String uri = extractImage(button);
  201. int code = extractKeycode(button);
  202. v = inflater.inflate(R.layout.custom_key, parent, false);
  203. ((KeyButtonView) v).setCode(code);
  204. if (uri != null) {
  205. ((KeyButtonView) v).loadAsync(uri);
  206. }
  207. } else {
  208. return null;
  209. }
  210. if (size != 0) {
  211. ViewGroup.LayoutParams params = v.getLayoutParams();
  212. params.width = (int) (params.width * size);
  213. }
  214. parent.addView(v);
  215. addToDispatchers(v);
  216. View lastView = landscape ? mLastRot90 : mLastRot0;
  217. if (lastView != null) {
  218. v.setAccessibilityTraversalAfter(lastView.getId());
  219. }
  220. if (landscape) {
  221. mLastRot90 = v;
  222. } else {
  223. mLastRot0 = v;
  224. }
  225. return v;
  226. }
  227. public static String extractImage(String buttonSpec) {
  228. if (!buttonSpec.contains(KEY_IMAGE_DELIM)) {
  229. return null;
  230. }
  231. final int start = buttonSpec.indexOf(KEY_IMAGE_DELIM);
  232. String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_CODE_END));
  233. return subStr;
  234. }
  235. public static int extractKeycode(String buttonSpec) {
  236. if (!buttonSpec.contains(KEY_CODE_START)) {
  237. return 1;
  238. }
  239. final int start = buttonSpec.indexOf(KEY_CODE_START);
  240. String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_IMAGE_DELIM));
  241. return Integer.parseInt(subStr);
  242. }
  243. public static float extractSize(String buttonSpec) {
  244. if (!buttonSpec.contains(SIZE_MOD_START)) {
  245. return 1;
  246. }
  247. final int sizeStart = buttonSpec.indexOf(SIZE_MOD_START);
  248. String sizeStr = buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
  249. return Float.parseFloat(sizeStr);
  250. }
  251. public static String extractButton(String buttonSpec) {
  252. if (!buttonSpec.contains(SIZE_MOD_START)) {
  253. return buttonSpec;
  254. }
  255. return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
  256. }
  257. private void addToDispatchers(View v) {
  258. if (mButtonDispatchers != null) {
  259. final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
  260. if (indexOfKey >= 0) {
  261. mButtonDispatchers.valueAt(indexOfKey).addView(v);
  262. } else if (v instanceof ViewGroup) {
  263. final ViewGroup viewGroup = (ViewGroup)v;
  264. final int N = viewGroup.getChildCount();
  265. for (int i = 0; i < N; i++) {
  266. addToDispatchers(viewGroup.getChildAt(i));
  267. }
  268. }
  269. }
  270. }
  271. private boolean isSw600Dp() {
  272. Configuration configuration = mContext.getResources().getConfiguration();
  273. return (configuration.smallestScreenWidthDp >= 600);
  274. }
  275. /**
  276. * This manually sets the width of sw600dp landscape buttons because despite
  277. * overriding the configuration from the overridden resources aren't loaded currently.
  278. */
  279. private void setupLandButton(View v) {
  280. Resources res = mContext.getResources();
  281. v.getLayoutParams().width = res.getDimensionPixelOffset(
  282. R.dimen.navigation_key_width_sw600dp_land);
  283. int padding = res.getDimensionPixelOffset(R.dimen.navigation_key_padding_sw600dp_land);
  284. v.setPadding(padding, v.getPaddingTop(), padding, v.getPaddingBottom());
  285. }
  286. private void clearViews() {
  287. if (mButtonDispatchers != null) {
  288. for (int i = 0; i < mButtonDispatchers.size(); i++) {
  289. mButtonDispatchers.valueAt(i).clear();
  290. }
  291. }
  292. clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
  293. clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
  294. }
  295. private void clearAllChildren(ViewGroup group) {
  296. for (int i = 0; i < group.getChildCount(); i++) {
  297. ((ViewGroup) group.getChildAt(i)).removeAllViews();
  298. }
  299. }
  300. }

  分析:

       1. 这段代码比较简单,文中也有做一些注释,主要功能就是把90度和0度的布局同时添加到ViewGroup中,那这个两个布局既然同时添加到ViewGroup,为什么我看到的只有一种布局文件呢?这是通过setVisibility(View.VISIBLE)来实现,这个功能的实现在NavigationBarView中的updateCurrentView()。

     2.导航栏的三个按键的布局文件分别为:back.xml 、home.xml 、recent_apps.xml. 这个三个布局文件都是KeyButtonView ,而KeyButtonView继承ImageView,所以想修改返回键、Home、近期列表这三个键的UI,只需要更换对应的图片。

    back.xml

  1. <com.android.systemui.statusbar.policy.KeyButtonView
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:systemui="http://schemas.android.com/apk/res-auto"
  4. android:id="@+id/back"
  5. android:layout_width="@dimen/navigation_key_width"
  6. android:layout_height="match_parent"
  7. android:layout_weight="0"
  8. android:src="@drawable/ic_sysbar_back"
  9. systemui:keyCode="4"
  10. android:scaleType="center"
  11. android:contentDescription="@string/accessibility_back"
  12. android:paddingStart="@dimen/navigation_key_padding"
  13. android:paddingEnd="@dimen/navigation_key_padding"
  14. />

由于三个布局文件很相近就不一 一列举,@drawable/ic_sysbar_back就是系统所使用的返回键图片,而keyCode=4与系统定义的KEY_BACK相同,因此系统才知道你按back键是让它返回上个界面而不是回到主界面。

   KeyButtonView

  1. public class KeyButtonView extends ImageView {
  2. private int mContentDescriptionRes;
  3. private long mDownTime;
  4. private int mCode;
  5. private int mTouchSlop;
  6. private boolean mSupportsLongpress = true;
  7. private AudioManager mAudioManager;
  8. private boolean mGestureAborted;
  9. private boolean mLongClicked;
  10. private final Runnable mCheckLongPress = new Runnable() {
  11. public void run() {
  12. if (isPressed()) {
  13. // Log.d("KeyButtonView", "longpressed: " + this);
  14. if (isLongClickable()) {
  15. // Just an old-fashioned ImageView
  16. performLongClick();
  17. mLongClicked = true;
  18. } else if (mSupportsLongpress) {
  19. sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
  20. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
  21. mLongClicked = true;
  22. }
  23. }
  24. }
  25. };
  26. public KeyButtonView(Context context, AttributeSet attrs) {
  27. this(context, attrs, 0);
  28. }
  29. public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
  30. super(context, attrs);
  31. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
  32. defStyle, 0);
  33. mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
  34. mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
  35. TypedValue value = new TypedValue();
  36. if (a.getValue(R.styleable.KeyButtonView_android_contentDescription, value)) {
  37. mContentDescriptionRes = value.resourceId;
  38. }
  39. a.recycle();
  40. setClickable(true);
  41. mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
  42. mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
  43. setBackground(new KeyButtonRipple(context, this));
  44. }
  45. public void setCode(int code) {
  46. mCode = code;
  47. }
  48. public void loadAsync(String uri) {
  49. new AsyncTask<String, Void, Drawable>() {
  50. @Override
  51. protected Drawable doInBackground(String... params) {
  52. return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
  53. }
  54. @Override
  55. protected void onPostExecute(Drawable drawable) {
  56. setImageDrawable(drawable);
  57. }
  58. }.execute(uri);
  59. }
  60. @Override
  61. protected void onConfigurationChanged(Configuration newConfig) {
  62. super.onConfigurationChanged(newConfig);
  63. if (mContentDescriptionRes != 0) {
  64. setContentDescription(mContext.getString(mContentDescriptionRes));
  65. }
  66. }
  67. @Override
  68. public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  69. super.onInitializeAccessibilityNodeInfo(info);
  70. if (mCode != 0) {
  71. info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
  72. if (mSupportsLongpress || isLongClickable()) {
  73. info.addAction(
  74. new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
  75. }
  76. }
  77. }
  78. @Override
  79. protected void onWindowVisibilityChanged(int visibility) {
  80. super.onWindowVisibilityChanged(visibility);
  81. if (visibility != View.VISIBLE) {
  82. jumpDrawablesToCurrentState();
  83. }
  84. }
  85. @Override
  86. public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
  87. if (action == ACTION_CLICK && mCode != 0) {
  88. sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
  89. sendEvent(KeyEvent.ACTION_UP, 0);
  90. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  91. playSoundEffect(SoundEffectConstants.CLICK);
  92. return true;
  93. } else if (action == ACTION_LONG_CLICK && mCode != 0) {
  94. sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
  95. sendEvent(KeyEvent.ACTION_UP, 0);
  96. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
  97. return true;
  98. }
  99. return super.performAccessibilityActionInternal(action, arguments);
  100. }
  101. public boolean onTouchEvent(MotionEvent ev) {
  102. final int action = ev.getAction();
  103. int x, y;
  104. if (action == MotionEvent.ACTION_DOWN) {
  105. mGestureAborted = false;
  106. }
  107. if (mGestureAborted) {
  108. return false;
  109. }
  110. switch (action) {
  111. case MotionEvent.ACTION_DOWN:
  112. mDownTime = SystemClock.uptimeMillis();
  113. mLongClicked = false;
  114. setPressed(true);
  115. if (mCode != 0) {
  116. sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);//发送事件给inputmanager
  117. } else {
  118. // Provide the same haptic feedback that the system offers for virtual keys.
  119. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
  120. }
  121. removeCallbacks(mCheckLongPress);
  122. postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());//执行长按事件
  123. break;
  124. case MotionEvent.ACTION_MOVE:
  125. x = (int)ev.getX();
  126. y = (int)ev.getY();
  127. setPressed(x >= -mTouchSlop
  128. && x < getWidth() + mTouchSlop
  129. && y >= -mTouchSlop
  130. && y < getHeight() + mTouchSlop);
  131. break;
  132. case MotionEvent.ACTION_CANCEL:
  133. setPressed(false);
  134. if (mCode != 0) {
  135. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
  136. }
  137. removeCallbacks(mCheckLongPress);
  138. break;
  139. case MotionEvent.ACTION_UP:
  140. final boolean doIt = isPressed() && !mLongClicked;
  141. setPressed(false);
  142. if (mCode != 0) {
  143. if (doIt) {
  144. sendEvent(KeyEvent.ACTION_UP, 0);
  145. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  146. playSoundEffect(SoundEffectConstants.CLICK);
  147. } else {
  148. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
  149. }
  150. } else {
  151. // no key code, just a regular ImageView
  152. if (doIt) {
  153. performClick();
  154. }
  155. }
  156. removeCallbacks(mCheckLongPress);
  157. break;
  158. }
  159. return true;
  160. }
  161. public void playSoundEffect(int soundConstant) {
  162. mAudioManager.playSoundEffect(soundConstant, ActivityManager.getCurrentUser());
  163. };
  164. public void sendEvent(int action, int flags) {
  165. sendEvent(action, flags, SystemClock.uptimeMillis());
  166. }
  167. void sendEvent(int action, int flags, long when) {
  168. final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
  169. final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
  170. 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
  171. flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
  172. InputDevice.SOURCE_KEYBOARD);
  173. InputManager.getInstance().injectInputEvent(ev,
  174. InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
  175. }
  176. public void abortCurrentGesture() {
  177. setPressed(false);
  178. mGestureAborted = true;
  179. }
  180. }

      分析:

               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);  中的mCode就是我们之前xml中所定义的。这样系统就能识别我们的意思。意义在于实现不同按键的功能

    NavigationBarView

            

  1. public class NavigationBarView extends LinearLayout {
  2. final static boolean DEBUG = false;
  3. final static String TAG = "PhoneStatusBar/NavigationBarView";
  4. // slippery nav bar when everything is disabled, e.g. during setup
  5. final static boolean SLIPPERY_WHEN_DISABLED = true;
  6. final Display mDisplay;
  7. View mCurrentView = null;
  8. View[] mRotatedViews = new View[4];
  9. boolean mVertical;
  10. boolean mScreenOn;
  11. boolean mShowMenu;
  12. int mDisabledFlags = 0;
  13. int mNavigationIconHints = 0;
  14. private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
  15. private Drawable mBackCarModeIcon, mBackLandCarModeIcon;
  16. private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
  17. private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
  18. private Drawable mRecentIcon;
  19. private Drawable mDockedIcon;
  20. private Drawable mImeIcon;
  21. private Drawable mMenuIcon;
  22. /// M: BMW @{
  23. private Drawable mRestoreIcon;
  24. private boolean mResizeMode;
  25. private boolean mRestoreShow;
  26. /// @}
  27. private NavigationBarGestureHelper mGestureHelper;
  28. private DeadZone mDeadZone;
  29. private final NavigationBarTransitions mBarTransitions;
  30. // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
  31. final static boolean WORKAROUND_INVALID_LAYOUT = true;
  32. final static int MSG_CHECK_INVALID_LAYOUT = 8686;
  33. // performs manual animation in sync with layout transitions
  34. private final NavTransitionListener mTransitionListener = new NavTransitionListener();
  35. private OnVerticalChangedListener mOnVerticalChangedListener;
  36. private boolean mLayoutTransitionsEnabled = true;
  37. private boolean mWakeAndUnlocking;
  38. private boolean mCarMode = false;
  39. private boolean mDockedStackExists;
  40. private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
  41. private Configuration mConfiguration;
  42. // MPlugin for Navigation Bar
  43. private INavigationBarPlugin mNavBarPlugin;
  44. /// M: BMW @{
  45. private KeyguardViewMediator mKeyguardViewMediator;
  46. /// @}
  47. private class NavTransitionListener implements TransitionListener {
  48. private boolean mBackTransitioning;
  49. private boolean mHomeAppearing;
  50. private long mStartDelay;
  51. private long mDuration;
  52. private TimeInterpolator mInterpolator;
  53. @Override
  54. public void startTransition(LayoutTransition transition, ViewGroup container,
  55. View view, int transitionType) {
  56. if (view.getId() == R.id.back) {
  57. mBackTransitioning = true;
  58. } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
  59. mHomeAppearing = true;
  60. mStartDelay = transition.getStartDelay(transitionType);
  61. mDuration = transition.getDuration(transitionType);
  62. mInterpolator = transition.getInterpolator(transitionType);
  63. }
  64. }
  65. @Override
  66. public void endTransition(LayoutTransition transition, ViewGroup container,
  67. View view, int transitionType) {
  68. if (view.getId() == R.id.back) {
  69. mBackTransitioning = false;
  70. } else if (view.getId() == R.id.home && transitionType == LayoutTransition.APPEARING) {
  71. mHomeAppearing = false;
  72. }
  73. }
  74. public void onBackAltCleared() {
  75. ButtonDispatcher backButton = getBackButton();
  76. // When dismissing ime during unlock, force the back button to run the same appearance
  77. // animation as home (if we catch this condition early enough).
  78. if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
  79. && mHomeAppearing && getHomeButton().getAlpha() == 0) {
  80. getBackButton().setAlpha(0);
  81. ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
  82. a.setStartDelay(mStartDelay);
  83. a.setDuration(mDuration);
  84. a.setInterpolator(mInterpolator);
  85. a.start();
  86. }
  87. }
  88. }
  89. private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
  90. @Override
  91. public void onClick(View view) {
  92. mContext.getSystemService(InputMethodManager.class)
  93. .showInputMethodPicker(true /* showAuxiliarySubtypes */);
  94. }
  95. };
  96. private class H extends Handler {
  97. public void handleMessage(Message m) {
  98. switch (m.what) {
  99. case MSG_CHECK_INVALID_LAYOUT:
  100. final String how = "" + m.obj;
  101. final int w = getWidth();
  102. final int h = getHeight();
  103. final int vw = getCurrentView().getWidth();
  104. final int vh = getCurrentView().getHeight();
  105. if (h != vh || w != vw) {
  106. Log.w(TAG, String.format(
  107. "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
  108. how, w, h, vw, vh));
  109. if (WORKAROUND_INVALID_LAYOUT) {
  110. requestLayout();
  111. }
  112. }
  113. break;
  114. }
  115. }
  116. }
  117. public NavigationBarView(Context context, AttributeSet attrs) {
  118. super(context, attrs);
  119. mDisplay = ((WindowManager) context.getSystemService(
  120. Context.WINDOW_SERVICE)).getDefaultDisplay();
  121. mVertical = false;
  122. mShowMenu = false;
  123. mGestureHelper = new NavigationBarGestureHelper(context);//手势管理类
  124. mConfiguration = new Configuration();
  125. mConfiguration.updateFrom(context.getResources().getConfiguration());
  126. updateIcons(context, Configuration.EMPTY, mConfiguration);//加载更新图标
  127. // MPlugin Navigation Bar creation and initialization
  128. try {
  129. mNavBarPlugin = (INavigationBarPlugin) MPlugin.createInstance(
  130. INavigationBarPlugin.class.getName(), context);
  131. } catch (Exception e) {
  132. Log.e(TAG, "Catch INavigationBarPlugin exception: ", e);
  133. }
  134. if (mNavBarPlugin == null) {
  135. Log.d(TAG, "DefaultNavigationBarPlugin");
  136. mNavBarPlugin = new DefaultNavigationBarPlugin(context);
  137. }
  138. mBarTransitions = new NavigationBarTransitions(this);
  139. //返回键 、主页 、近期列表 三个按键的监听控制。
  140. mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
  141. mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
  142. mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
  143. /// M: BMW @{
  144. if (MultiWindowManager.isSupported()) {
  145. mButtonDisatchers.put(R.id.restore, new ButtonDispatcher(R.id.restore));
  146. mKeyguardViewMediator = ((SystemUIApplication)context)
  147. .getComponent(KeyguardViewMediator.class);
  148. }
  149. /// @}
  150. mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
  151. mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
  152. }
  153. public BarTransitions getBarTransitions() {
  154. return mBarTransitions;
  155. }
  156. public void setComponents(RecentsComponent recentsComponent, Divider divider) {
  157. mGestureHelper.setComponents(recentsComponent, divider, this);
  158. }
  159. public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
  160. mOnVerticalChangedListener = onVerticalChangedListener;
  161. notifyVerticalChangedListener(mVertical);
  162. }
  163. @Override
  164. public boolean onTouchEvent(MotionEvent event) {
  165. if (mGestureHelper.onTouchEvent(event)) {
  166. return true;
  167. }
  168. if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
  169. mDeadZone.poke(event);
  170. }
  171. return super.onTouchEvent(event);
  172. }
  173. @Override
  174. public boolean onInterceptTouchEvent(MotionEvent event) {
  175. return mGestureHelper.onInterceptTouchEvent(event);
  176. }
  177. public void abortCurrentGesture() {
  178. getHomeButton().abortCurrentGesture();
  179. }
  180. private H mHandler = new H();
  181. public View getCurrentView() {
  182. return mCurrentView;
  183. }
  184. public View[] getAllViews() {
  185. return mRotatedViews;
  186. }
  187. //TODO:: Temp remove plugin for build pass, need to add back
  188. public ButtonDispatcher getRecentsButton() {
  189. return mButtonDisatchers.get(R.id.recent_apps);
  190. }
  191. public ButtonDispatcher getMenuButton() {
  192. return mButtonDisatchers.get(R.id.menu);
  193. }
  194. public ButtonDispatcher getBackButton() {
  195. return mButtonDisatchers.get(R.id.back);
  196. }
  197. public ButtonDispatcher getHomeButton() {
  198. return mButtonDisatchers.get(R.id.home);
  199. }
  200. public ButtonDispatcher getImeSwitchButton() {
  201. return mButtonDisatchers.get(R.id.ime_switcher);
  202. }
  203. /// M: BMW @{
  204. public ButtonDispatcher getRestoreButton() {
  205. return mButtonDisatchers.get(R.id.restore);
  206. }
  207. /// @}
  208. private void updateCarModeIcons(Context ctx) {
  209. mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode);
  210. mBackLandCarModeIcon = mBackCarModeIcon;
  211. mBackAltCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime_carmode);
  212. mBackAltLandCarModeIcon = mBackAltCarModeIcon;
  213. mHomeCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_home_carmode);
  214. }
  215. private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
  216. if (oldConfig.orientation != newConfig.orientation
  217. || oldConfig.densityDpi != newConfig.densityDpi) {
  218. mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
  219. }
  220. if (oldConfig.densityDpi != newConfig.densityDpi) {
  221. mBackIcon = ctx.getDrawable(R.drawable.ic_sysbar_back);
  222. mBackLandIcon = mBackIcon;
  223. mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime);
  224. mBackAltLandIcon = mBackAltIcon;
  225. mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
  226. mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
  227. mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
  228. mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
  229. /// M: BMW @{
  230. if (MultiWindowManager.isSupported()) {
  231. mRestoreIcon = ctx.getDrawable(R.drawable.ic_sysbar_restore);
  232. }
  233. /// @}
  234. updateCarModeIcons(ctx);
  235. }
  236. }
  237. @Override
  238. public void setLayoutDirection(int layoutDirection) {
  239. // Reload all the icons
  240. updateIcons(getContext(), Configuration.EMPTY, mConfiguration);
  241. super.setLayoutDirection(layoutDirection);
  242. }
  243. public void notifyScreenOn(boolean screenOn) {
  244. mScreenOn = screenOn;
  245. setDisabledFlags(mDisabledFlags, true);
  246. }
  247. public void setNavigationIconHints(int hints) {
  248. setNavigationIconHints(hints, false);
  249. }
  250. private Drawable getBackIconWithAlt(boolean carMode, boolean landscape) {
  251. return landscape
  252. ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
  253. : carMode ? mBackAltCarModeIcon : mBackAltIcon;
  254. }
  255. private Drawable getBackIcon(boolean carMode, boolean landscape) {
  256. return landscape
  257. ? carMode ? mBackLandCarModeIcon : mBackLandIcon
  258. : carMode ? mBackCarModeIcon : mBackIcon;
  259. }
  260. public void setNavigationIconHints(int hints, boolean force) {
  261. if (!force && hints == mNavigationIconHints) return;
  262. final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
  263. if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
  264. mTransitionListener.onBackAltCleared();
  265. }
  266. if (DEBUG) {
  267. android.widget.Toast.makeText(getContext(),
  268. "Navigation icon hints = " + hints,
  269. 500).show();
  270. }
  271. mNavigationIconHints = hints;
  272. // We have to replace or restore the back and home button icons when exiting or entering
  273. // carmode, respectively. Recents are not available in CarMode in nav bar so change
  274. // to recent icon is not required.
  275. Drawable backIcon = (backAlt)
  276. ? getBackIconWithAlt(mCarMode, mVertical)
  277. : getBackIcon(mCarMode, mVertical);
  278. /// M: Support plugin customize.
  279. //getBackButton().setImageDrawable(backIcon);
  280. getBackButton().setImageDrawable(mNavBarPlugin.getBackImage(backIcon));//设置返回图标
  281. updateRecentsIcon();//最近列表图标
  282. /// M: BMW @{
  283. if (MultiWindowManager.isSupported()) {
  284. updateRestoreIcon();
  285. }
  286. /// @}
  287. //设置home图标
  288. if (mCarMode) {
  289. getHomeButton().setImageDrawable(mHomeCarModeIcon);
  290. } else {
  291. /// M: Support plugin customize.
  292. //getHomeButton().setImageDrawable(mHomeDefaultIcon);
  293. getHomeButton().setImageDrawable(mNavBarPlugin.getHomeImage(mHomeDefaultIcon));
  294. }
  295. final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
  296. getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
  297. getImeSwitchButton().setImageDrawable(mImeIcon);
  298. // Update menu button in case the IME state has changed.
  299. setMenuVisibility(mShowMenu, true);
  300. getMenuButton().setImageDrawable(mMenuIcon);
  301. setDisabledFlags(mDisabledFlags, true);
  302. }
  303. public void setDisabledFlags(int disabledFlags) {
  304. setDisabledFlags(disabledFlags, false);
  305. }
  306. public void setDisabledFlags(int disabledFlags, boolean force) {
  307. if (!force && mDisabledFlags == disabledFlags) return;
  308. mDisabledFlags = disabledFlags;
  309. final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
  310. // Disable recents always in car mode.
  311. boolean disableRecent = (
  312. mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
  313. final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
  314. && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
  315. final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
  316. if (SLIPPERY_WHEN_DISABLED) {
  317. setSlippery(disableHome && disableRecent && disableBack && disableSearch);
  318. }
  319. ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
  320. if (navButtons != null) {
  321. LayoutTransition lt = navButtons.getLayoutTransition();
  322. if (lt != null) {
  323. if (!lt.getTransitionListeners().contains(mTransitionListener)) {
  324. lt.addTransitionListener(mTransitionListener);
  325. }
  326. }
  327. }
  328. if (inLockTask() && disableRecent && !disableHome) {
  329. // Don't hide recents when in lock task, it is used for exiting.
  330. // Unless home is hidden, then in DPM locked mode and no exit available.
  331. disableRecent = false;
  332. }
  333. getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
  334. getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
  335. getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
  336. /// M: BMW @{
  337. //hide restore when keyguard is showing
  338. if (MultiWindowManager.isSupported() && mKeyguardViewMediator != null) {
  339. boolean isKeyguardShowing = mKeyguardViewMediator.isShowing();
  340. mResizeMode = mRestoreShow && !isKeyguardShowing;
  341. updateRestoreIcon();
  342. }
  343. /// @}
  344. }
  345. private boolean inLockTask() {
  346. try {
  347. return ActivityManagerNative.getDefault().isInLockTaskMode();
  348. } catch (RemoteException e) {
  349. return false;
  350. }
  351. }
  352. public void setLayoutTransitionsEnabled(boolean enabled) {
  353. mLayoutTransitionsEnabled = enabled;
  354. updateLayoutTransitionsEnabled();
  355. }
  356. public void setWakeAndUnlocking(boolean wakeAndUnlocking) {
  357. setUseFadingAnimations(wakeAndUnlocking);
  358. mWakeAndUnlocking = wakeAndUnlocking;
  359. updateLayoutTransitionsEnabled();
  360. }
  361. private void updateLayoutTransitionsEnabled() {
  362. boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
  363. ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
  364. LayoutTransition lt = navButtons.getLayoutTransition();
  365. if (lt != null) {
  366. if (enabled) {
  367. lt.enableTransitionType(LayoutTransition.APPEARING);
  368. lt.enableTransitionType(LayoutTransition.DISAPPEARING);
  369. lt.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
  370. lt.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
  371. } else {
  372. lt.disableTransitionType(LayoutTransition.APPEARING);
  373. lt.disableTransitionType(LayoutTransition.DISAPPEARING);
  374. lt.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
  375. lt.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
  376. }
  377. }
  378. }
  379. private void setUseFadingAnimations(boolean useFadingAnimations) {
  380. WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
  381. if (lp != null) {
  382. boolean old = lp.windowAnimations != 0;
  383. if (!old && useFadingAnimations) {
  384. lp.windowAnimations = R.style.Animation_NavigationBarFadeIn;
  385. } else if (old && !useFadingAnimations) {
  386. lp.windowAnimations = 0;
  387. } else {
  388. return;
  389. }
  390. WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
  391. wm.updateViewLayout(this, lp);
  392. }
  393. }
  394. public void setSlippery(boolean newSlippery) {
  395. WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
  396. if (lp != null) {
  397. boolean oldSlippery = (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0;
  398. if (!oldSlippery && newSlippery) {
  399. lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
  400. } else if (oldSlippery && !newSlippery) {
  401. lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
  402. } else {
  403. return;
  404. }
  405. WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
  406. wm.updateViewLayout(this, lp);
  407. }
  408. }
  409. public void setMenuVisibility(final boolean show) {
  410. setMenuVisibility(show, false);
  411. }
  412. public void setMenuVisibility(final boolean show, final boolean force) {
  413. if (!force && mShowMenu == show) return;
  414. mShowMenu = show;
  415. // Only show Menu if IME switcher not shown.
  416. final boolean shouldShow = mShowMenu &&
  417. ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
  418. getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
  419. }
  420. @Override
  421. public void onFinishInflate() {
  422. updateRotatedViews();
  423. ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers(
  424. mButtonDisatchers);
  425. getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
  426. try {
  427. WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
  428. @Override
  429. public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
  430. }
  431. @Override
  432. public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
  433. mHandler.post(new Runnable() {
  434. @Override
  435. public void run() {
  436. mDockedStackExists = exists;
  437. updateRecentsIcon();//最近列表图标变化的更改。
  438. }
  439. });
  440. }
  441. @Override
  442. public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
  443. throws RemoteException {
  444. }
  445. @Override
  446. public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
  447. throws RemoteException {
  448. }
  449. @Override
  450. public void onDockSideChanged(int newDockSide) throws RemoteException {
  451. }
  452. });
  453. } catch (RemoteException e) {
  454. Log.e(TAG, "Failed registering docked stack exists listener", e);
  455. }
  456. /// M: BMW restore button @{
  457. if (MultiWindowManager.isSupported()) {
  458. try {
  459. WindowManagerGlobal.getWindowManagerService()
  460. .registerFreeformStackListener(new IFreeformStackListener.Stub() {
  461. @Override
  462. public void onShowRestoreButtonChanged(final boolean isShown)
  463. throws RemoteException {
  464. mHandler.post(new Runnable() {
  465. @Override
  466. public void run() {
  467. //hide restore when keyguard is showing
  468. boolean isKeyguardShowing = false;
  469. if (mKeyguardViewMediator != null) {
  470. isKeyguardShowing = mKeyguardViewMediator.isShowing();
  471. }
  472. mRestoreShow = isShown;
  473. mResizeMode = isShown && !isKeyguardShowing;
  474. updateRestoreIcon();
  475. }
  476. });
  477. }
  478. });
  479. } catch (RemoteException e) {
  480. Log.e(TAG, "Failed registering freeform stack exists listener", e);
  481. }
  482. }
  483. /// @}
  484. }
  485. /// M: BMW restore button @{
  486. private void updateRestoreIcon() {
  487. if (MultiWindowManager.DEBUG)
  488. Log.d(TAG, "BMW, updateRestoreIcon, mResizeMode = " + mResizeMode);
  489. getRestoreButton().setImageDrawable(mRestoreIcon);
  490. getRestoreButton().setVisibility(mResizeMode ? View.VISIBLE : View.INVISIBLE);
  491. }
  492. /// @}
  493. void updateRotatedViews() {
  494. mRotatedViews[Surface.ROTATION_0] =
  495. mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
  496. mRotatedViews[Surface.ROTATION_270] =
  497. mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
  498. updateCurrentView();
  499. }
  500. private void updateCurrentView() {
  501. //获取旋转角度,在控制树之前会对所以的view进行gone
  502. final int rot = mDisplay.getRotation();
  503. for (int i=0; i<4; i++) {
  504. mRotatedViews[i].setVisibility(View.GONE);
  505. }
  506. mCurrentView = mRotatedViews[rot];
  507. mCurrentView.setVisibility(View.VISIBLE);
  508. for (int i = 0; i < mButtonDisatchers.size(); i++) {
  509. mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
  510. }
  511. //加载时候的动画显示
  512. updateLayoutTransitionsEnabled();
  513. }
  514. private void updateRecentsIcon() {
  515. /// M: Support plugin customize.
  516. //getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
  517. getRecentsButton().setImageDrawable(
  518. mNavBarPlugin.getRecentImage(mDockedStackExists ? mDockedIcon : mRecentIcon));
  519. }
  520. public boolean isVertical() {
  521. return mVertical;
  522. }
  523. public void reorient() {
  524. updateCurrentView();
  525. getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
  526. mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);//死亡区域
  527. // force the low profile & disabled states into compliance
  528. mBarTransitions.init();
  529. setDisabledFlags(mDisabledFlags, true /* force */);//禁用一些功能。
  530. setMenuVisibility(mShowMenu, true /* force */);//设置菜单的可见性
  531. if (DEBUG) {
  532. Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
  533. }
  534. updateTaskSwitchHelper();
  535. setNavigationIconHints(mNavigationIconHints, true);//修改图标
  536. }
  537. private void updateTaskSwitchHelper() {
  538. boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
  539. mGestureHelper.setBarState(mVertical, isRtl);
  540. }
  541. @Override
  542. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  543. if (DEBUG) Log.d(TAG, String.format(
  544. "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
  545. final boolean newVertical = w > 0 && h > w;//检查当前是水平还是竖直。
  546. //当方向变化时,
  547. if (newVertical != mVertical) {
  548. mVertical = newVertical;
  549. //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
  550. reorient();
  551. notifyVerticalChangedListener(newVertical);
  552. }
  553. postCheckForInvalidLayout("sizeChanged");
  554. super.onSizeChanged(w, h, oldw, oldh);
  555. }
  556. private void notifyVerticalChangedListener(boolean newVertical) {
  557. if (mOnVerticalChangedListener != null) {
  558. mOnVerticalChangedListener.onVerticalChanged(newVertical);
  559. }
  560. }
  561. @Override
  562. protected void onConfigurationChanged(Configuration newConfig) {
  563. super.onConfigurationChanged(newConfig);
  564. boolean uiCarModeChanged = updateCarMode(newConfig);
  565. updateTaskSwitchHelper();
  566. updateIcons(getContext(), mConfiguration, newConfig);
  567. updateRecentsIcon();
  568. if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi) {
  569. // If car mode or density changes, we need to reset the icons.
  570. setNavigationIconHints(mNavigationIconHints, true);
  571. }
  572. mConfiguration.updateFrom(newConfig);
  573. }
  574. /**
  575. * If the configuration changed, update the carmode and return that it was updated.
  576. */
  577. private boolean updateCarMode(Configuration newConfig) {
  578. boolean uiCarModeChanged = false;
  579. if (newConfig != null) {
  580. int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
  581. if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
  582. mCarMode = false;
  583. uiCarModeChanged = true;
  584. } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
  585. mCarMode = true;
  586. uiCarModeChanged = true;
  587. }
  588. }
  589. return uiCarModeChanged;
  590. }
  591. /*
  592. @Override
  593. protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
  594. if (DEBUG) Log.d(TAG, String.format(
  595. "onLayout: %s (%d,%d,%d,%d)",
  596. changed?"changed":"notchanged", left, top, right, bottom));
  597. super.onLayout(changed, left, top, right, bottom);
  598. }
  599. // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
  600. // fails, any touch on the display will fix the layout.
  601. @Override
  602. public boolean onInterceptTouchEvent(MotionEvent ev) {
  603. if (DEBUG) Log.d(TAG, "onInterceptTouchEvent: " + ev.toString());
  604. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  605. postCheckForInvalidLayout("touch");
  606. }
  607. return super.onInterceptTouchEvent(ev);
  608. }
  609. */
  610. private String getResourceName(int resId) {
  611. if (resId != 0) {
  612. final android.content.res.Resources res = getContext().getResources();
  613. try {
  614. return res.getResourceName(resId);
  615. } catch (android.content.res.Resources.NotFoundException ex) {
  616. return "(unknown)";
  617. }
  618. } else {
  619. return "(null)";
  620. }
  621. }
  622. private void postCheckForInvalidLayout(final String how) {
  623. mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
  624. }
  625. private static String visibilityToString(int vis) {
  626. switch (vis) {
  627. case View.INVISIBLE:
  628. return "INVISIBLE";
  629. case View.GONE:
  630. return "GONE";
  631. default:
  632. return "VISIBLE";
  633. }
  634. }
  635. public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  636. pw.println("NavigationBarView {");
  637. final Rect r = new Rect();
  638. final Point size = new Point();
  639. mDisplay.getRealSize(size);
  640. pw.println(String.format(" this: " + PhoneStatusBar.viewInfo(this)
  641. + " " + visibilityToString(getVisibility())));
  642. getWindowVisibleDisplayFrame(r);
  643. final boolean offscreen = r.right > size.x || r.bottom > size.y;
  644. pw.println(" window: "
  645. + r.toShortString()
  646. + " " + visibilityToString(getWindowVisibility())
  647. + (offscreen ? " OFFSCREEN!" : ""));
  648. pw.println(String.format(" mCurrentView: id=%s (%dx%d) %s",
  649. getResourceName(getCurrentView().getId()),
  650. getCurrentView().getWidth(), getCurrentView().getHeight(),
  651. visibilityToString(getCurrentView().getVisibility())));
  652. pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
  653. mDisabledFlags,
  654. mVertical ? "true" : "false",
  655. mShowMenu ? "true" : "false"));
  656. dumpButton(pw, "back", getBackButton());
  657. dumpButton(pw, "home", getHomeButton());
  658. dumpButton(pw, "rcnt", getRecentsButton());
  659. dumpButton(pw, "menu", getMenuButton());
  660. pw.println(" }");
  661. }
  662. private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
  663. pw.print(" " + caption + ": ");
  664. if (button == null) {
  665. pw.print("null");
  666. } else {
  667. pw.print(visibilityToString(button.getVisibility())
  668. + " alpha=" + button.getAlpha()
  669. );
  670. }
  671. pw.println();
  672. }
  673. public interface OnVerticalChangedListener {
  674. void onVerticalChanged(boolean isVertical);
  675. }
  676. }

    分析:

              1.在这里面我们可以控制不同方向的导航栏布局

             2  导航栏的图片的显示。

            

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/219293
推荐阅读
相关标签
  

闽ICP备14008679号