1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.content.Context;
22import android.os.ServiceManager;
23import android.view.MotionEvent;
24import android.view.View;
25import android.view.animation.AccelerateInterpolator;
26
27import com.android.internal.statusbar.IStatusBarService;
28import com.android.systemui.R;
29import com.android.systemui.statusbar.policy.KeyButtonView;
30
31public final class NavigationBarTransitions extends BarTransitions {
32
33    private static final int CONTENT_FADE_DURATION = 200;
34
35    private final NavigationBarView mView;
36    private final IStatusBarService mBarService;
37
38    private boolean mLightsOut;
39    private boolean mVertical;
40    private int mRequestedMode;
41
42    public NavigationBarTransitions(NavigationBarView view) {
43        super(view, R.drawable.nav_background);
44        mView = view;
45        mBarService = IStatusBarService.Stub.asInterface(
46                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
47    }
48
49    public void init(boolean isVertical) {
50        setVertical(isVertical);
51        applyModeBackground(-1, getMode(), false /*animate*/);
52        applyMode(getMode(), false /*animate*/, true /*force*/);
53    }
54
55    public void setVertical(boolean isVertical) {
56        mVertical = isVertical;
57        transitionTo(mRequestedMode, false /*animate*/);
58    }
59
60    @Override
61    public void transitionTo(int mode, boolean animate) {
62        mRequestedMode = mode;
63        if (mVertical) {
64            // translucent mode not allowed when vertical
65            if (mode == MODE_TRANSLUCENT || mode == MODE_TRANSPARENT) {
66                mode = MODE_OPAQUE;
67            } else if (mode == MODE_LIGHTS_OUT_TRANSPARENT) {
68                mode = MODE_LIGHTS_OUT;
69            }
70        }
71        super.transitionTo(mode, animate);
72    }
73
74    @Override
75    protected void onTransition(int oldMode, int newMode, boolean animate) {
76        super.onTransition(oldMode, newMode, animate);
77        applyMode(newMode, animate, false /*force*/);
78    }
79
80    private void applyMode(int mode, boolean animate, boolean force) {
81        // apply to key buttons
82        final float alpha = alphaForMode(mode);
83        setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
84        setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
85        setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
86        setKeyButtonViewQuiescentAlpha(mView.getImeSwitchButton(), alpha, animate);
87
88        applyBackButtonQuiescentAlpha(mode, animate);
89
90        // apply to lights out
91        applyLightsOut(isLightsOut(mode), animate, force);
92    }
93
94    private float alphaForMode(int mode) {
95        final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
96        return isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
97    }
98
99    public void applyBackButtonQuiescentAlpha(int mode, boolean animate) {
100        float backAlpha = 0;
101        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton());
102        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton());
103        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton());
104        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getImeSwitchButton());
105        if (backAlpha > 0) {
106            setKeyButtonViewQuiescentAlpha(mView.getBackButton(), backAlpha, animate);
107        }
108    }
109
110    private static float maxVisibleQuiescentAlpha(float max, View v) {
111        if ((v instanceof KeyButtonView) && v.isShown()) {
112            return Math.max(max, ((KeyButtonView)v).getQuiescentAlpha());
113        }
114        return max;
115    }
116
117    private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
118        if (button instanceof KeyButtonView) {
119            ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
120        }
121    }
122
123    private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
124        if (!force && lightsOut == mLightsOut) return;
125
126        mLightsOut = lightsOut;
127
128        final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
129        final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
130
131        // ok, everyone, stop it right there
132        navButtons.animate().cancel();
133        lowLights.animate().cancel();
134
135        final float navButtonsAlpha = lightsOut ? 0f : 1f;
136        final float lowLightsAlpha = lightsOut ? 1f : 0f;
137
138        if (!animate) {
139            navButtons.setAlpha(navButtonsAlpha);
140            lowLights.setAlpha(lowLightsAlpha);
141            lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
142        } else {
143            final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
144            navButtons.animate()
145                .alpha(navButtonsAlpha)
146                .setDuration(duration)
147                .start();
148
149            lowLights.setOnTouchListener(mLightsOutListener);
150            if (lowLights.getVisibility() == View.GONE) {
151                lowLights.setAlpha(0f);
152                lowLights.setVisibility(View.VISIBLE);
153            }
154            lowLights.animate()
155                .alpha(lowLightsAlpha)
156                .setDuration(duration)
157                .setInterpolator(new AccelerateInterpolator(2.0f))
158                .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
159                    @Override
160                    public void onAnimationEnd(Animator _a) {
161                        lowLights.setVisibility(View.GONE);
162                    }
163                })
164                .start();
165        }
166    }
167
168    private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
169        @Override
170        public boolean onTouch(View v, MotionEvent ev) {
171            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
172                // even though setting the systemUI visibility below will turn these views
173                // on, we need them to come up faster so that they can catch this motion
174                // event
175                applyLightsOut(false, false, false);
176
177                try {
178                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
179                            "LightsOutListener");
180                } catch (android.os.RemoteException ex) {
181                }
182            }
183            return false;
184        }
185    };
186}
187