1 /*
2  * Copyright (C) 2016 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 
17 package com.android.calculator2;
18 
19 import android.content.Context;
20 import android.transition.Fade;
21 import android.transition.Transition;
22 import android.transition.TransitionManager;
23 import android.util.AttributeSet;
24 import android.view.GestureDetector;
25 import android.view.MotionEvent;
26 import android.view.View;
27 import android.view.accessibility.AccessibilityManager;
28 import android.widget.LinearLayout;
29 import android.widget.Toolbar;
30 
31 public class CalculatorDisplay extends LinearLayout
32         implements AccessibilityManager.AccessibilityStateChangeListener {
33 
34     /**
35      * The duration in milliseconds after which to hide the toolbar.
36      */
37     private static final long AUTO_HIDE_DELAY_MILLIS = 3000L;
38 
39     /**
40      * The duration in milliseconds to fade in/out the toolbar.
41      */
42     private static final long FADE_DURATION = 200L;
43 
44     private final Runnable mHideToolbarRunnable = new Runnable() {
45         @Override
46         public void run() {
47             // Remove any duplicate callbacks to hide the toolbar.
48             removeCallbacks(this);
49 
50             // Only animate if we have been laid out at least once.
51             if (isLaidOut()) {
52                 TransitionManager.beginDelayedTransition(CalculatorDisplay.this, mTransition);
53             }
54             mToolbar.setVisibility(View.INVISIBLE);
55         }
56     };
57 
58     private final AccessibilityManager mAccessibilityManager;
59     private final GestureDetector mTapDetector;
60 
61     private Toolbar mToolbar;
62     private Transition mTransition;
63 
64     private boolean mForceToolbarVisible;
65 
CalculatorDisplay(Context context)66     public CalculatorDisplay(Context context) {
67         this(context, null /* attrs */);
68     }
69 
CalculatorDisplay(Context context, AttributeSet attrs)70     public CalculatorDisplay(Context context, AttributeSet attrs) {
71         this(context, attrs, 0 /* defStyleAttr */);
72     }
73 
CalculatorDisplay(Context context, AttributeSet attrs, int defStyleAttr)74     public CalculatorDisplay(Context context, AttributeSet attrs, int defStyleAttr) {
75         super(context, attrs, defStyleAttr);
76 
77         mAccessibilityManager =
78                 (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
79 
80         mTapDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
81             @Override
82             public boolean onDown(MotionEvent e) {
83                 // Remove callbacks to hide the toolbar.
84                 removeCallbacks(mHideToolbarRunnable);
85 
86                 return true;
87             }
88 
89             @Override
90             public boolean onSingleTapConfirmed(MotionEvent e) {
91                 if (mToolbar.getVisibility() != View.VISIBLE) {
92                     showToolbar(true);
93                 } else {
94                     hideToolbar();
95                 }
96 
97                 return true;
98             }
99         });
100 
101         // Draw the children in reverse order so that the toolbar is on top.
102         setChildrenDrawingOrderEnabled(true);
103     }
104 
105     @Override
onFinishInflate()106     protected void onFinishInflate() {
107         super.onFinishInflate();
108 
109         mToolbar = (Toolbar) findViewById(R.id.toolbar);
110         mTransition = new Fade()
111                 .setDuration(FADE_DURATION)
112                 .addTarget(mToolbar);
113     }
114 
115     @Override
getChildDrawingOrder(int childCount, int i)116     protected int getChildDrawingOrder(int childCount, int i) {
117         // Reverse the normal drawing order.
118         return (childCount - 1) - i;
119     }
120 
121     @Override
onAttachedToWindow()122     protected void onAttachedToWindow() {
123         super.onAttachedToWindow();
124         mAccessibilityManager.addAccessibilityStateChangeListener(this);
125     }
126 
127     @Override
onDetachedFromWindow()128     protected void onDetachedFromWindow() {
129         super.onDetachedFromWindow();
130         mAccessibilityManager.removeAccessibilityStateChangeListener(this);
131     }
132 
133     @Override
onAccessibilityStateChanged(boolean enabled)134     public void onAccessibilityStateChanged(boolean enabled) {
135         // Always show the toolbar whenever accessibility is enabled.
136         showToolbar(true);
137     }
138 
139     @Override
onInterceptTouchEvent(MotionEvent event)140     public boolean onInterceptTouchEvent(MotionEvent event) {
141         mTapDetector.onTouchEvent(event);
142         return super.onInterceptTouchEvent(event);
143     }
144 
145     @Override
onTouchEvent(MotionEvent event)146     public boolean onTouchEvent(MotionEvent event) {
147         return mTapDetector.onTouchEvent(event) || super.onTouchEvent(event);
148     }
149 
150     /**
151      * Returns {@code true} if the toolbar should remain visible.
152      */
getForceToolbarVisible()153     public boolean getForceToolbarVisible() {
154         return mForceToolbarVisible || mAccessibilityManager.isEnabled();
155     }
156 
157     /**
158      * Forces the toolbar to remain visible.
159      *
160      * @param forceToolbarVisible {@code true} to keep the toolbar visible
161      */
setForceToolbarVisible(boolean forceToolbarVisible)162     public void setForceToolbarVisible(boolean forceToolbarVisible) {
163         if (mForceToolbarVisible != forceToolbarVisible) {
164             mForceToolbarVisible = forceToolbarVisible;
165             showToolbar(!forceToolbarVisible);
166         }
167     }
168 
169     /**
170      * Shows the toolbar.
171      * @param autoHide Automatically ide toolbar again after delay
172      */
showToolbar(boolean autoHide)173     public void showToolbar(boolean autoHide) {
174         // Only animate if we have been laid out at least once.
175         if (isLaidOut()) {
176             TransitionManager.beginDelayedTransition(this, mTransition);
177         }
178         mToolbar.setVisibility(View.VISIBLE);
179 
180         // Remove callbacks to hide the toolbar.
181         removeCallbacks(mHideToolbarRunnable);
182 
183         // Auto hide the toolbar after 3 seconds.
184         if (autoHide && !getForceToolbarVisible()) {
185             postDelayed(mHideToolbarRunnable, AUTO_HIDE_DELAY_MILLIS);
186         }
187     }
188 
189     /**
190      * Hides the toolbar.
191      */
hideToolbar()192     public void hideToolbar() {
193         if (!getForceToolbarVisible()) {
194             removeCallbacks(mHideToolbarRunnable);
195             mHideToolbarRunnable.run();
196         }
197     }
198 
isToolbarVisible()199     public boolean isToolbarVisible() {
200         return mToolbar.getVisibility() == View.VISIBLE;
201     }
202 }
203