| /* |
| * 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 android.animation.Animator; |
| import android.animation.AnimatorSet; |
| import android.animation.AnimatorListenerAdapter; |
| import android.animation.ObjectAnimator; |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.os.ServiceManager; |
| import android.util.AttributeSet; |
| import android.util.Slog; |
| import android.view.animation.AccelerateInterpolator; |
| import android.view.Display; |
| import android.view.KeyEvent; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.Surface; |
| import android.view.WindowManager; |
| import android.widget.LinearLayout; |
| import android.content.res.Configuration; |
| |
| import com.android.internal.statusbar.IStatusBarService; |
| |
| import com.android.systemui.R; |
| |
| 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]; |
| AnimatorSet mLastAnimator = null; |
| |
| int mBarSize; |
| boolean mVertical; |
| |
| boolean mHidden, mLowProfile; |
| int mDisabledFlags = 0; |
| |
| public View getRecentsButton() { |
| return mCurrentView.findViewById(R.id.recent_apps); |
| } |
| |
| public View getMenuButton() { |
| return mCurrentView.findViewById(R.id.menu); |
| } |
| |
| 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; |
| } |
| |
| 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); |
| } catch (android.os.RemoteException ex) { |
| } |
| } |
| return false; |
| } |
| }; |
| |
| public void setDisabledFlags(int disabledFlags) { |
| setDisabledFlags(disabledFlags, false); |
| } |
| |
| public void setDisabledFlags(int disabledFlags, boolean force) { |
| if (!force && mDisabledFlags == disabledFlags) return; |
| |
| mDisabledFlags = disabledFlags; |
| |
| final boolean disableNavigation = ((disabledFlags & View.STATUS_BAR_DISABLE_NAVIGATION) != 0); |
| final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0); |
| |
| getBackButton() .setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE); |
| getHomeButton() .setVisibility(disableNavigation ? View.INVISIBLE : View.VISIBLE); |
| getRecentsButton().setVisibility(disableNavigation ? View.INVISIBLE : View.VISIBLE); |
| getMenuButton() .setVisibility(disableNavigation ? View.INVISIBLE : View.VISIBLE); |
| } |
| |
| 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 ? 600 : 200) |
| .start(); |
| |
| lowLights.setOnTouchListener(mLightsOutListener); |
| if (lowLights.getVisibility() == View.GONE) { |
| lowLights.setAlpha(0f); |
| lowLights.setVisibility(View.VISIBLE); |
| } |
| lowLights.animate() |
| .alpha(lightsOut ? 1f : 0f) |
| .setStartDelay(lightsOut ? 500 : 0) |
| .setDuration(lightsOut ? 1000 : 300) |
| .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); |
| |
| if (!ANIMATE_HIDE_TRANSITION) { |
| setVisibility(hide ? View.GONE : View.VISIBLE); |
| return; |
| } |
| |
| float oldAlpha = mCurrentView.getAlpha(); |
| if (DEBUG) { |
| Slog.d(TAG, "animating alpha: " + oldAlpha + " -> " |
| + (!hide ? 1f : 0f)); |
| } |
| |
| if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel(); |
| |
| if (!hide) { |
| setVisibility(View.VISIBLE); |
| } |
| |
| // play us off, animatorset |
| mLastAnimator = new AnimatorSet(); |
| mLastAnimator.playTogether( |
| ObjectAnimator.ofFloat(mCurrentView, "alpha", hide ? 0f : 1f), |
| ObjectAnimator.ofFloat(mCurrentView, |
| mVertical ? "translationX" : "translationY", |
| hide ? mBarSize : 0) |
| ); |
| mLastAnimator.setDuration(!hide ? 250 : 1000); |
| mLastAnimator.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator _a) { |
| mLastAnimator = null; |
| if (hide) { |
| setVisibility(View.GONE); |
| } |
| } |
| }); |
| mLastAnimator.start(); |
| } |
| |
| public void onFinishInflate() { |
| 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]; |
| } |
| |
| @Override |
| public boolean onTouchEvent(MotionEvent ev) { |
| try { |
| mBarService.setSystemUiVisibility(0); |
| } catch (android.os.RemoteException ex) { |
| } |
| return false; // pass it on |
| } |
| |
| public void reorient() { |
| final int rot = mDisplay.getRotation(); |
| for (int i=0; i<4; i++) { |
| mRotatedViews[i].setVisibility(View.GONE); |
| } |
| mCurrentView = mRotatedViews[rot]; |
| mCurrentView.setVisibility(View.VISIBLE); |
| mVertical = (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270); |
| |
| // force the low profile & disabled states into compliance |
| setLowProfile(mLowProfile, false, true /* force */); |
| setDisabledFlags(mDisabledFlags, true /* force */); |
| |
| if (DEBUG_DEADZONE) { |
| mCurrentView.findViewById(R.id.deadzone).setBackgroundColor(0x808080FF); |
| } |
| |
| if (DEBUG) { |
| Slog.d(TAG, "reorient(): rot=" + mDisplay.getRotation()); |
| } |
| } |
| } |