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 && (mode == MODE_TRANSLUCENT || mode == MODE_TRANSPARENT)) {
64            // translucent mode not allowed when vertical
65            mode = MODE_OPAQUE;
66        }
67        super.transitionTo(mode, animate);
68    }
69
70    @Override
71    protected void onTransition(int oldMode, int newMode, boolean animate) {
72        super.onTransition(oldMode, newMode, animate);
73        applyMode(newMode, animate, false /*force*/);
74    }
75
76    private void applyMode(int mode, boolean animate, boolean force) {
77        // apply to key buttons
78        final float alpha = alphaForMode(mode);
79        setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
80        setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
81        setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
82        setKeyButtonViewQuiescentAlpha(mView.getImeSwitchButton(), alpha, animate);
83
84        applyBackButtonQuiescentAlpha(mode, animate);
85
86        // apply to lights out
87        applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
88    }
89
90    private float alphaForMode(int mode) {
91        final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
92        return isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
93    }
94
95    public void applyBackButtonQuiescentAlpha(int mode, boolean animate) {
96        float backAlpha = 0;
97        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton());
98        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton());
99        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton());
100        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getImeSwitchButton());
101        if (backAlpha > 0) {
102            setKeyButtonViewQuiescentAlpha(mView.getBackButton(), backAlpha, animate);
103        }
104    }
105
106    private static float maxVisibleQuiescentAlpha(float max, View v) {
107        if ((v instanceof KeyButtonView) && v.isShown()) {
108            return Math.max(max, ((KeyButtonView)v).getQuiescentAlpha());
109        }
110        return max;
111    }
112
113    private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
114        if (button instanceof KeyButtonView) {
115            ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
116        }
117    }
118
119    private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
120        if (!force && lightsOut == mLightsOut) return;
121
122        mLightsOut = lightsOut;
123
124        final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
125        final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
126
127        // ok, everyone, stop it right there
128        navButtons.animate().cancel();
129        lowLights.animate().cancel();
130
131        final float navButtonsAlpha = lightsOut ? 0f : 1f;
132        final float lowLightsAlpha = lightsOut ? 1f : 0f;
133
134        if (!animate) {
135            navButtons.setAlpha(navButtonsAlpha);
136            lowLights.setAlpha(lowLightsAlpha);
137            lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
138        } else {
139            final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
140            navButtons.animate()
141                .alpha(navButtonsAlpha)
142                .setDuration(duration)
143                .start();
144
145            lowLights.setOnTouchListener(mLightsOutListener);
146            if (lowLights.getVisibility() == View.GONE) {
147                lowLights.setAlpha(0f);
148                lowLights.setVisibility(View.VISIBLE);
149            }
150            lowLights.animate()
151                .alpha(lowLightsAlpha)
152                .setDuration(duration)
153                .setInterpolator(new AccelerateInterpolator(2.0f))
154                .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
155                    @Override
156                    public void onAnimationEnd(Animator _a) {
157                        lowLights.setVisibility(View.GONE);
158                    }
159                })
160                .start();
161        }
162    }
163
164    private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
165        @Override
166        public boolean onTouch(View v, MotionEvent ev) {
167            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
168                // even though setting the systemUI visibility below will turn these views
169                // on, we need them to come up faster so that they can catch this motion
170                // event
171                applyLightsOut(false, false, false);
172
173                try {
174                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE);
175                } catch (android.os.RemoteException ex) {
176                }
177            }
178            return false;
179        }
180    };
181}
182