/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.phone; import java.io.File; import java.net.URISyntaxException; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.StatusBarManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; import android.util.TypedValue; import android.view.animation.AccelerateInterpolator; import android.view.Display; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.Surface; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.StringBuilder; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.R; import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.DelegateViewHelper; import com.android.systemui.statusbar.policy.KeyButtonView; import com.android.systemui.statusbar.policy.ExtensibleKeyButtonView; public class NavigationBarView extends LinearLayout { final static boolean DEBUG = false; final static String TAG = "PhoneStatusBar/NavigationBarView"; final static boolean DEBUG_DEADZONE = false; final static boolean NAVBAR_ALWAYS_AT_RIGHT = true; final static boolean ANIMATE_HIDE_TRANSITION = false; // turned off because it introduces unsightly delay when videos goes to full screen protected IStatusBarService mBarService; final Display mDisplay; View mCurrentView = null; View[] mRotatedViews = new View[4]; int mBarSize; boolean mVertical; boolean mHidden, mLowProfile, mShowMenu; int mDisabledFlags = 0; int mNavigationIconHints = 0; private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon; private DelegateViewHelper mDelegateHelper; // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288) final static boolean WORKAROUND_INVALID_LAYOUT = true; final static int MSG_CHECK_INVALID_LAYOUT = 8686; // Navbar Custom Targets defines. final static String ACTION_HOME = "**home**"; final static String ACTION_BACK = "**back**"; final static String ACTION_SEARCH = "**search**"; final static String ACTION_MENU = "**menu**"; final static String ACTION_POWER = "**power**"; final static String ACTION_NOTIFICATIONS = "**notifications**"; final static String ACTION_RECENTS = "**recents**"; final static String ACTION_IME = "**ime**"; final static String ACTION_KILL = "**kill**"; final static String ACTION_NULL = "**null**"; int mNumberOfButtons = 3; /* 0 = Phone UI * 1 = Tablet UI * 2 = Phablet UI */ int mTablet_UI = 0; public String[] mClickActions = new String[7]; public String[] mLongpressActions = new String[7]; public String[] mPortraitIcons = new String[7]; public final static int StockButtonsQty = 3; public final static String[] StockClickActions = { "**back**", "**home**", "**recents**", "**null**", "**null**", "**null**", "**null**" }; public final static String[] StockLongpress = { "**null**", "**null**", "**null**", "**null**", "**null**", "**null**", "**null**" }; FrameLayout rot0; FrameLayout rot90; //Definitions for NavBar Menu button customization public final static int SHOW_LEFT_MENU = 1; public final static int SHOW_RIGHT_MENU = 0; public final static int SHOW_BOTH_MENU = 2; public final static int SHOW_DONT = 4; public final static int VISIBILITY_SYSTEM = 0; public final static int VISIBILITY_SYSTEM_AND_INVIZ = 3; public final static int VISIBILITY_NEVER = 1; public final static int VISIBILITY_ALWAYS = 2; public static final int KEY_MENU_RIGHT = 2; public static final int KEY_MENU_LEFT = 5; private int currentVisibility; private int currentSetting; private class H extends Handler { public void handleMessage(Message m) { switch (m.what) { case MSG_CHECK_INVALID_LAYOUT: final String how = "" + m.obj; final int w = getWidth(); final int h = getHeight(); final int vw = mCurrentView.getWidth(); final int vh = mCurrentView.getHeight(); if (h != vh || w != vw) { Slog.w(TAG, String.format( "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)", how, w, h, vw, vh)); if (WORKAROUND_INVALID_LAYOUT) { requestLayout(); } } break; } } } public void setDelegateView(View view) { mDelegateHelper.setDelegateView(view); } public void setBar(BaseStatusBar phoneStatusBar) { mDelegateHelper.setBar(phoneStatusBar); } @Override public boolean onTouchEvent(MotionEvent event) { if (mDelegateHelper != null) { mDelegateHelper.onInterceptTouchEvent(event); } return true; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { return mDelegateHelper.onInterceptTouchEvent(event); } private H mHandler = new H(); public View getLeftMenuButton() { return mCurrentView.findViewById(R.id.menu_left); } public View getRightMenuButton() { return mCurrentView.findViewById(R.id.menu); } public View getRecentsButton() { return mCurrentView.findViewById(R.id.recent_apps); } public View getBackButton() { return mCurrentView.findViewById(R.id.back); } public View getHomeButton() { return mCurrentView.findViewById(R.id.home); } public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); mHidden = false; mDisplay = ((WindowManager)context.getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay(); mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); final Resources res = mContext.getResources(); mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size); mVertical = false; mShowMenu = false; mDelegateHelper = new DelegateViewHelper(this); mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back); mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land); mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime); mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime); } private void makeBar() { ((LinearLayout) rot0.findViewById(R.id.nav_buttons)).removeAllViews(); ((LinearLayout) rot0.findViewById(R.id.lights_out)).removeAllViews(); ((LinearLayout) rot90.findViewById(R.id.nav_buttons)).removeAllViews(); ((LinearLayout) rot90.findViewById(R.id.lights_out)).removeAllViews(); for (int i = 0; i <= 1; i++) { boolean landscape = (i == 1); LinearLayout navButtonLayout = (LinearLayout) (landscape ? rot90 .findViewById(R.id.nav_buttons) : rot0 .findViewById(R.id.nav_buttons)); LinearLayout lightsOut = (LinearLayout) (landscape ? rot90 .findViewById(R.id.lights_out) : rot0 .findViewById(R.id.lights_out)); // add left menu if (currentSetting != SHOW_DONT) { View leftmenuKey = generateKey(landscape, KEY_MENU_LEFT); addButton(navButtonLayout, leftmenuKey, landscape); addLightsOutButton(lightsOut, leftmenuKey, landscape, true); } for (int j = 0; j < mNumberOfButtons; j++) { ExtensibleKeyButtonView v = generateKey(landscape, mClickActions[j], mLongpressActions[j], mPortraitIcons[j]); v.setTag((landscape ? "key_land_" : "key_") + j); addButton(navButtonLayout, v, landscape); addLightsOutButton(lightsOut, v, landscape, false); if (v.getId() == R.id.back){ mBackIcon = mBackLandIcon = v.getDrawable(); } if (mNumberOfButtons == 3 && j != (mNumberOfButtons - 1)) { // add separator view here View separator = new View(mContext); separator.setLayoutParams(getSeparatorLayoutParams(landscape)); addButton(navButtonLayout, separator, landscape); addLightsOutButton(lightsOut, separator, landscape, true); } } if (currentSetting != SHOW_DONT) { View rightMenuKey = generateKey(landscape, KEY_MENU_RIGHT); addButton(navButtonLayout, rightMenuKey, landscape); addLightsOutButton(lightsOut, rightMenuKey, landscape, true); } } } private void addLightsOutButton(LinearLayout root, View v, boolean landscape, boolean empty) { ImageView addMe = new ImageView(mContext); addMe.setLayoutParams(v.getLayoutParams()); addMe.setImageResource(empty ? R.drawable.ic_sysbar_lights_out_dot_large : R.drawable.ic_sysbar_lights_out_dot_small); addMe.setScaleType(ImageView.ScaleType.CENTER); addMe.setVisibility(empty ? View.INVISIBLE : View.VISIBLE); if (landscape) root.addView(addMe, 0); else root.addView(addMe); } private void addButton(ViewGroup root, View addMe, boolean landscape) { if (landscape) root.addView(addMe, 0); else root.addView(addMe); } private View generateKey(boolean landscape, int keyId) { KeyButtonView v = null; Resources r = getResources(); int btnWidth = 80; switch (keyId) { case KEY_MENU_RIGHT: v = new KeyButtonView(mContext, null); v.setLayoutParams(getLayoutParams(landscape, 40)); v.setId(R.id.menu); v.setCode(KeyEvent.KEYCODE_MENU); v.setImageResource(landscape ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); v.setVisibility(View.INVISIBLE); v.setContentDescription(r.getString(R.string.accessibility_menu)); v.setGlowBackground(landscape ? R.drawable.ic_sysbar_highlight_land : R.drawable.ic_sysbar_highlight); return v; case KEY_MENU_LEFT: v = new KeyButtonView(mContext, null); v.setLayoutParams(getLayoutParams(landscape, 40)); v.setId(R.id.menu_left); v.setCode(KeyEvent.KEYCODE_MENU); v.setImageResource(landscape ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); v.setVisibility(View.INVISIBLE); v.setContentDescription(r.getString(R.string.accessibility_menu)); v.setGlowBackground(landscape ? R.drawable.ic_sysbar_highlight_land : R.drawable.ic_sysbar_highlight); return v; } return null; } private ExtensibleKeyButtonView generateKey(boolean landscape, String clickAction, String longpress, String iconUri) { final int iconSize = 80; ExtensibleKeyButtonView v = new ExtensibleKeyButtonView(mContext, null, clickAction, longpress); Log.i("key.ext", "generated ex key: " + clickAction); v.setLayoutParams(getLayoutParams(landscape, iconSize)); boolean drawableSet = false; if (iconUri != null) { if (iconUri.length() > 0) { // custom icon from the URI here File f = new File(Uri.parse(iconUri).getPath()); if (f.exists()) { v.setImageDrawable(new BitmapDrawable(getResources(), f.getAbsolutePath())); drawableSet = true; } } if (!drawableSet && clickAction != null && !clickAction.startsWith("**")) { // here it's not a system action (**action**), so it must be an // app intent try { Drawable d = mContext.getPackageManager().getActivityIcon( Intent.parseUri(clickAction, 0)); final int[] appIconPadding = getAppIconPadding(); if (landscape) v.setPaddingRelative(appIconPadding[1], appIconPadding[0], appIconPadding[3], appIconPadding[2]); else v.setPaddingRelative(appIconPadding[0], appIconPadding[1], appIconPadding[2], appIconPadding[3]); v.setImageDrawable(d); drawableSet = true; } catch (NameNotFoundException e) { e.printStackTrace(); drawableSet = false; } catch (URISyntaxException e) { e.printStackTrace(); drawableSet = false; } } } if (!drawableSet) { v.setImageDrawable(getNavbarIconImage(landscape, clickAction)); } v.setGlowBackground(landscape ? R.drawable.ic_sysbar_highlight_land : R.drawable.ic_sysbar_highlight); return v; } private int[] getAppIconPadding() { int[] padding = new int[4]; // left padding[0] = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources() .getDisplayMetrics()); // top padding[1] = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources() .getDisplayMetrics()); // right padding[2] = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources() .getDisplayMetrics()); // bottom padding[3] = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources() .getDisplayMetrics()); return padding; } private LayoutParams getLayoutParams(boolean landscape, float dp) { float px = dp * getResources().getDisplayMetrics().density; return landscape ? new LayoutParams(LayoutParams.MATCH_PARENT, (int) px, 1f) : new LayoutParams((int) px, LayoutParams.MATCH_PARENT, 1f); } private LayoutParams getSeparatorLayoutParams(boolean landscape) { float px = 25 * getResources().getDisplayMetrics().density; return landscape ? new LayoutParams(LayoutParams.MATCH_PARENT, (int) px) : new LayoutParams((int) px, LayoutParams.MATCH_PARENT); } View.OnTouchListener mLightsOutListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { // even though setting the systemUI visibility below will turn these views // on, we need them to come up faster so that they can catch this motion // event setLowProfile(false, false, false); try { mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); } catch (android.os.RemoteException ex) { } } return false; } }; public void setNavigationIconHints(int hints) { setNavigationIconHints(hints, false); } public void setNavigationIconHints(int hints, boolean force) { if (!force && hints == mNavigationIconHints) return; if (DEBUG) { android.widget.Toast.makeText(mContext, "Navigation icon hints = " + hints, 500).show(); } mNavigationIconHints = hints; // We can't gaurantee users will set these buttons as targets if (getBackButton() != null) { getBackButton().setAlpha( (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f); ((ImageView)getBackButton()).setImageDrawable( (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT)) ? (mVertical ? mBackAltLandIcon : mBackAltIcon) : (mVertical ? mBackLandIcon : mBackIcon)); } if (getHomeButton()!=null) { getHomeButton().setAlpha( (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f); } if (getRecentsButton()!=null) { getRecentsButton().setAlpha( (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f); } } public void setDisabledFlags(int disabledFlags) { setDisabledFlags(disabledFlags, false); } public void setDisabledFlags(int disabledFlags, boolean force) { if (!force && mDisabledFlags == disabledFlags) return; mDisabledFlags = disabledFlags; final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0); final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0); final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0); setSlippery(disableHome && disableRecent && disableBack); for (int j = 0; j < mNumberOfButtons; j++) { View v = (View) findViewWithTag((mVertical ? "key_land_" : "key_") + j); if (v != null) { int vid = v.getId(); if (vid == R.id.back) { v.setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE); } else if (vid == R.id.recent_apps) { v.setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); } else { // treat all other buttons as same rule as home v.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE); } } } } public void setSlippery(boolean newSlippery) { WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); if (lp != null) { boolean oldSlippery = (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0; if (!oldSlippery && newSlippery) { lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY; } else if (oldSlippery && !newSlippery) { lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY; } else { return; } WindowManagerImpl.getDefault().updateViewLayout(this, lp); } } public void setMenuVisibility(final boolean show) { setMenuVisibility(show, false); } public void setMenuVisibility(final boolean show, final boolean force) { if (!force && mShowMenu == show) return; if (currentSetting == SHOW_DONT) { return; } mShowMenu = show; boolean localShow = show; ImageView leftButton = (ImageView) getLeftMenuButton(); ImageView rightButton = (ImageView) getRightMenuButton(); switch (currentVisibility) { case VISIBILITY_SYSTEM: leftButton .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); rightButton .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); break; case VISIBILITY_ALWAYS: leftButton .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); rightButton .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); localShow = true; break; case VISIBILITY_NEVER: leftButton .setImageResource(R.drawable.ic_sysbar_menu_inviz); rightButton .setImageResource(R.drawable.ic_sysbar_menu_inviz); localShow = true; break; case VISIBILITY_SYSTEM_AND_INVIZ: if (localShow) { leftButton .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); ((ImageView) getRightMenuButton()) .setImageResource(mVertical ? R.drawable.ic_sysbar_menu_land : R.drawable.ic_sysbar_menu); } else { localShow = true; leftButton .setImageResource(R.drawable.ic_sysbar_menu_inviz); rightButton .setImageResource(R.drawable.ic_sysbar_menu_inviz); } break; } // do this after just in case show was changed switch (currentSetting) { case SHOW_BOTH_MENU: getLeftMenuButton().setVisibility(localShow ? View.VISIBLE : View.INVISIBLE); getRightMenuButton().setVisibility(localShow ? View.VISIBLE : View.INVISIBLE); break; case SHOW_LEFT_MENU: getLeftMenuButton().setVisibility(localShow ? View.VISIBLE : View.INVISIBLE); getRightMenuButton().setVisibility(View.INVISIBLE); break; default: case SHOW_RIGHT_MENU: getLeftMenuButton().setVisibility(View.INVISIBLE); getRightMenuButton().setVisibility(localShow ? View.VISIBLE : View.INVISIBLE); break; } } public void setLowProfile(final boolean lightsOut) { setLowProfile(lightsOut, true, false); } public void setLowProfile(final boolean lightsOut, final boolean animate, final boolean force) { if (!force && lightsOut == mLowProfile) return; mLowProfile = lightsOut; if (DEBUG) Slog.d(TAG, "setting lights " + (lightsOut?"out":"on")); final View navButtons = mCurrentView.findViewById(R.id.nav_buttons); final View lowLights = mCurrentView.findViewById(R.id.lights_out); // ok, everyone, stop it right there navButtons.animate().cancel(); lowLights.animate().cancel(); if (!animate) { navButtons.setAlpha(lightsOut ? 0f : 1f); lowLights.setAlpha(lightsOut ? 1f : 0f); lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE); } else { navButtons.animate() .alpha(lightsOut ? 0f : 1f) .setDuration(lightsOut ? 750 : 250) .start(); lowLights.setOnTouchListener(mLightsOutListener); if (lowLights.getVisibility() == View.GONE) { lowLights.setAlpha(0f); lowLights.setVisibility(View.VISIBLE); } lowLights.animate() .alpha(lightsOut ? 1f : 0f) .setDuration(lightsOut ? 750 : 250) .setInterpolator(new AccelerateInterpolator(2.0f)) .setListener(lightsOut ? null : new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator _a) { lowLights.setVisibility(View.GONE); } }) .start(); } } public void setHidden(final boolean hide) { if (hide == mHidden) return; mHidden = hide; Slog.d(TAG, (hide ? "HIDING" : "SHOWING") + " navigation bar"); // bring up the lights no matter what setLowProfile(false); } @Override public void onFinishInflate() { rot0 = (FrameLayout) findViewById(R.id.rot0); rot90 = (FrameLayout) findViewById(R.id.rot90); mRotatedViews[Surface.ROTATION_0] = mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0); mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90); mRotatedViews[Surface.ROTATION_270] = NAVBAR_ALWAYS_AT_RIGHT ? findViewById(R.id.rot90) : findViewById(R.id.rot270); for (View v : mRotatedViews) { // this helps avoid drawing artifacts with glowing navigation keys ViewGroup group = (ViewGroup) v.findViewById(R.id.nav_buttons); group.setMotionEventSplittingEnabled(false); } mCurrentView = mRotatedViews[Surface.ROTATION_0]; // this takes care of making the buttons SettingsObserver settingsObserver = new SettingsObserver(new Handler()); settingsObserver.observe(); } public void reorient() { final int rot = mDisplay.getRotation(); for (int i=0; i<4; i++) { mRotatedViews[i].setVisibility(View.GONE); } if (mTablet_UI !=0) { // this is either a tablet of Phablet. Need to stay at Rot_0 mCurrentView = mRotatedViews[Surface.ROTATION_0]; } else { mCurrentView = mRotatedViews[rot]; } mCurrentView.setVisibility(View.VISIBLE); // force the low profile & disabled states into compliance setLowProfile(mLowProfile, false, true /* force */); setDisabledFlags(mDisabledFlags, true /* force */); setMenuVisibility(mShowMenu, true /* force */); if (DEBUG_DEADZONE) { mCurrentView.findViewById(R.id.deadzone).setBackgroundColor(0x808080FF); } if (DEBUG) { Slog.d(TAG, "reorient(): rot=" + mDisplay.getRotation()); } setNavigationIconHints(mNavigationIconHints, true); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton()); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (DEBUG) Slog.d(TAG, String.format( "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh)); final boolean newVertical = w > 0 && h > w; if (newVertical != mVertical) { mVertical = newVertical; //Slog.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n")); reorient(); } postCheckForInvalidLayout("sizeChanged"); super.onSizeChanged(w, h, oldw, oldh); } /* @Override protected void onLayout (boolean changed, int left, int top, int right, int bottom) { if (DEBUG) Slog.d(TAG, String.format( "onLayout: %s (%d,%d,%d,%d)", changed?"changed":"notchanged", left, top, right, bottom)); super.onLayout(changed, left, top, right, bottom); } // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else // fails, any touch on the display will fix the layout. @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (DEBUG) Slog.d(TAG, "onInterceptTouchEvent: " + ev.toString()); if (ev.getAction() == MotionEvent.ACTION_DOWN) { postCheckForInvalidLayout("touch"); } return super.onInterceptTouchEvent(ev); } */ class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { super(handler); } void observe() { ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver( Settings.System.getUriFor(Settings.System.MENU_LOCATION), false, this); resolver.registerContentObserver( Settings.System.getUriFor(Settings.System.MENU_VISIBILITY), false, this); resolver.registerContentObserver( Settings.System.getUriFor(Settings.System.NAVIGATION_BAR_BUTTONS_QTY), false, this); for (int j = 0; j < 7; j++) { // watch all 5 settings for changes. resolver.registerContentObserver( Settings.System.getUriFor(Settings.System.NAVIGATION_CUSTOM_ACTIVITIES[j]), false, this); resolver.registerContentObserver( Settings.System .getUriFor(Settings.System.NAVIGATION_LONGPRESS_ACTIVITIES[j]), false, this); resolver.registerContentObserver( Settings.System.getUriFor(Settings.System.NAVIGATION_CUSTOM_APP_ICONS[j]), false, this); } updateSettings(); } @Override public void onChange(boolean selfChange) { updateSettings(); } } protected void updateSettings() { ContentResolver resolver = mContext.getContentResolver(); currentSetting = Settings.System.getInt(resolver, Settings.System.MENU_LOCATION, SHOW_RIGHT_MENU); currentVisibility = Settings.System.getInt(resolver, Settings.System.MENU_VISIBILITY, VISIBILITY_SYSTEM); mTablet_UI = Settings.System.getInt(resolver, Settings.System.TABLET_UI,0); mNumberOfButtons = Settings.System.getInt(resolver, Settings.System.NAVIGATION_BAR_BUTTONS_QTY, 0); if (mNumberOfButtons == 0) { mNumberOfButtons = StockButtonsQty; Settings.System.putInt(resolver, Settings.System.NAVIGATION_BAR_BUTTONS_QTY, StockButtonsQty); } for (int j = 0; j < 7; j++) { mClickActions[j] = Settings.System.getString(resolver, Settings.System.NAVIGATION_CUSTOM_ACTIVITIES[j]); if (mClickActions[j] == null) { mClickActions[j] = StockClickActions[j]; Settings.System.putString(resolver, Settings.System.NAVIGATION_CUSTOM_ACTIVITIES[j], mClickActions[j]); } mLongpressActions[j] = Settings.System.getString(resolver, Settings.System.NAVIGATION_LONGPRESS_ACTIVITIES[j]); if (mLongpressActions[j] == null) { mLongpressActions[j] = StockLongpress[j]; Settings.System.putString(resolver, Settings.System.NAVIGATION_LONGPRESS_ACTIVITIES[j], mLongpressActions[j]); } mPortraitIcons[j] = Settings.System.getString(resolver, Settings.System.NAVIGATION_CUSTOM_APP_ICONS[j]); if (mPortraitIcons[j] == null) { mPortraitIcons[j] = ""; Settings.System.putString(resolver, Settings.System.NAVIGATION_CUSTOM_APP_ICONS[j], ""); } } makeBar(); } private Drawable getNavbarIconImage(boolean landscape, String uri) { if (uri == null) return getResources().getDrawable(R.drawable.ic_sysbar_null); if (uri.startsWith("**")) { if (uri.equals(ACTION_HOME)) { return getResources().getDrawable(R.drawable.ic_sysbar_home); } else if (uri.equals(ACTION_BACK)) { return getResources().getDrawable(R.drawable.ic_sysbar_back); } else if (uri.equals(ACTION_RECENTS)) { return getResources().getDrawable(R.drawable.ic_sysbar_recent); } else if (uri.equals(ACTION_SEARCH)) { return getResources().getDrawable(R.drawable.ic_sysbar_search); } else if (uri.equals(ACTION_MENU)) { return getResources().getDrawable(R.drawable.ic_sysbar_menu_big); } else if (uri.equals(ACTION_IME)) { return getResources().getDrawable(R.drawable.ic_sysbar_ime_switcher); } else if (uri.equals(ACTION_KILL)) { return getResources().getDrawable(R.drawable.ic_sysbar_killtask); } else if (uri.equals(ACTION_POWER)) { return getResources().getDrawable(R.drawable.ic_sysbar_power); } else if (uri.equals(ACTION_NOTIFICATIONS)) { return getResources().getDrawable(R.drawable.ic_sysbar_notifications); } } return getResources().getDrawable(R.drawable.ic_sysbar_null); } private String getResourceName(int resId) { if (resId != 0) { final android.content.res.Resources res = mContext.getResources(); try { return res.getResourceName(resId); } catch (android.content.res.Resources.NotFoundException ex) { return "(unknown)"; } } else { return "(null)"; } } private void postCheckForInvalidLayout(final String how) { mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget(); } private static String visibilityToString(int vis) { switch (vis) { case View.INVISIBLE: return "INVISIBLE"; case View.GONE: return "GONE"; default: return "VISIBLE"; } } }