• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.systemui.recents;
18 
19 import android.animation.ArgbEvaluator;
20 import android.animation.ValueAnimator;
21 import android.app.ActivityManager;
22 import android.app.ActivityManagerNative;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Configuration;
28 import android.graphics.PixelFormat;
29 import android.graphics.drawable.ColorDrawable;
30 import android.os.RemoteException;
31 import android.util.DisplayMetrics;
32 import android.view.Gravity;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.view.WindowManager;
36 import android.view.accessibility.AccessibilityManager;
37 import android.view.animation.DecelerateInterpolator;
38 import android.widget.Button;
39 import android.widget.FrameLayout;
40 import android.widget.LinearLayout;
41 import android.widget.TextView;
42 
43 import com.android.systemui.R;
44 
45 import java.util.ArrayList;
46 
47 public class ScreenPinningRequest implements View.OnClickListener {
48     private final Context mContext;
49 
50     private final AccessibilityManager mAccessibilityService;
51     private final WindowManager mWindowManager;
52 
53     private RequestWindowView mRequestWindow;
54 
ScreenPinningRequest(Context context)55     public ScreenPinningRequest(Context context) {
56         mContext = context;
57         mAccessibilityService = (AccessibilityManager)
58                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
59         mWindowManager = (WindowManager)
60                 mContext.getSystemService(Context.WINDOW_SERVICE);
61     }
62 
clearPrompt()63     public void clearPrompt() {
64         if (mRequestWindow != null) {
65             mWindowManager.removeView(mRequestWindow);
66             mRequestWindow = null;
67         }
68     }
69 
showPrompt(boolean allowCancel)70     public void showPrompt(boolean allowCancel) {
71         clearPrompt();
72 
73         mRequestWindow = new RequestWindowView(mContext, allowCancel);
74 
75         mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
76 
77         // show the confirmation
78         WindowManager.LayoutParams lp = getWindowLayoutParams();
79         mWindowManager.addView(mRequestWindow, lp);
80     }
81 
onConfigurationChanged()82     public void onConfigurationChanged() {
83         if (mRequestWindow != null) {
84             mRequestWindow.onConfigurationChanged();
85         }
86     }
87 
getWindowLayoutParams()88     private WindowManager.LayoutParams getWindowLayoutParams() {
89         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
90                 ViewGroup.LayoutParams.MATCH_PARENT,
91                 ViewGroup.LayoutParams.MATCH_PARENT,
92                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
93                 0
94                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
95                         | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
96                         | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
97                 ,
98                 PixelFormat.TRANSLUCENT);
99         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
100         lp.setTitle("ScreenPinningConfirmation");
101         lp.gravity = Gravity.FILL;
102         return lp;
103     }
104 
105     @Override
onClick(View v)106     public void onClick(View v) {
107         if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
108             try {
109                 ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();
110             } catch (RemoteException e) {}
111         }
112         clearPrompt();
113     }
114 
getRequestLayoutParams(boolean isLandscape)115     public FrameLayout.LayoutParams getRequestLayoutParams(boolean isLandscape) {
116         return new FrameLayout.LayoutParams(
117                 ViewGroup.LayoutParams.WRAP_CONTENT,
118                 ViewGroup.LayoutParams.WRAP_CONTENT,
119                 isLandscape ? (Gravity.CENTER_VERTICAL | Gravity.RIGHT)
120                             : (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
121     }
122 
123     private class RequestWindowView extends FrameLayout {
124         private static final int OFFSET_DP = 96;
125 
126         private final ColorDrawable mColor = new ColorDrawable(0);
127         private ValueAnimator mColorAnim;
128         private ViewGroup mLayout;
129         private boolean mShowCancel;
130 
RequestWindowView(Context context, boolean showCancel)131         public RequestWindowView(Context context, boolean showCancel) {
132             super(context);
133             setClickable(true);
134             setOnClickListener(ScreenPinningRequest.this);
135             setBackground(mColor);
136             mShowCancel = showCancel;
137         }
138 
139         @Override
onAttachedToWindow()140         public void onAttachedToWindow() {
141             DisplayMetrics metrics = new DisplayMetrics();
142             mWindowManager.getDefaultDisplay().getMetrics(metrics);
143             float density = metrics.density;
144             boolean isLandscape = isLandscapePhone(mContext);
145 
146             inflateView(isLandscape);
147             int bgColor = mContext.getColor(
148                     R.color.screen_pinning_request_window_bg);
149             if (ActivityManager.isHighEndGfx()) {
150                 mLayout.setAlpha(0f);
151                 if (isLandscape) {
152                     mLayout.setTranslationX(OFFSET_DP * density);
153                 } else {
154                     mLayout.setTranslationY(OFFSET_DP * density);
155                 }
156                 mLayout.animate()
157                         .alpha(1f)
158                         .translationX(0)
159                         .translationY(0)
160                         .setDuration(300)
161                         .setInterpolator(new DecelerateInterpolator())
162                         .start();
163 
164                 mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, bgColor);
165                 mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
166                     @Override
167                     public void onAnimationUpdate(ValueAnimator animation) {
168                         final int c = (Integer) animation.getAnimatedValue();
169                         mColor.setColor(c);
170                     }
171                 });
172                 mColorAnim.setDuration(1000);
173                 mColorAnim.start();
174             } else {
175                 mColor.setColor(bgColor);
176             }
177 
178             IntentFilter filter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
179             filter.addAction(Intent.ACTION_USER_SWITCHED);
180             filter.addAction(Intent.ACTION_SCREEN_OFF);
181             mContext.registerReceiver(mReceiver, filter);
182         }
183 
isLandscapePhone(Context context)184         private boolean isLandscapePhone(Context context) {
185             Configuration config = mContext.getResources().getConfiguration();
186             return config.orientation == Configuration.ORIENTATION_LANDSCAPE
187                     && config.smallestScreenWidthDp < 600;
188         }
189 
inflateView(boolean isLandscape)190         private void inflateView(boolean isLandscape) {
191             // We only want this landscape orientation on <600dp, so rather than handle
192             // resource overlay for -land and -sw600dp-land, just inflate this
193             // other view for this single case.
194             mLayout = (ViewGroup) View.inflate(getContext(), isLandscape
195                     ? R.layout.screen_pinning_request_land_phone : R.layout.screen_pinning_request,
196                     null);
197             // Catch touches so they don't trigger cancel/activate, like outside does.
198             mLayout.setClickable(true);
199             // Status bar is always on the right.
200             mLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
201             // Buttons and text do switch sides though.
202             View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
203             buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
204             mLayout.findViewById(R.id.screen_pinning_text_area)
205                     .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
206             swapChildrenIfRtlAndVertical(buttons);
207 
208             ((Button) mLayout.findViewById(R.id.screen_pinning_ok_button))
209                     .setOnClickListener(ScreenPinningRequest.this);
210             if (mShowCancel) {
211                 ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
212                         .setOnClickListener(ScreenPinningRequest.this);
213             } else {
214                 ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
215                         .setVisibility(View.INVISIBLE);
216             }
217 
218             final int description = mAccessibilityService.isEnabled()
219                     ? R.string.screen_pinning_description_accessible
220                     : R.string.screen_pinning_description;
221             ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
222                     .setText(description);
223             final int backBgVisibility =
224                     mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
225             mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
226             mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
227 
228             addView(mLayout, getRequestLayoutParams(isLandscape));
229         }
230 
swapChildrenIfRtlAndVertical(View group)231         private void swapChildrenIfRtlAndVertical(View group) {
232             if (mContext.getResources().getConfiguration().getLayoutDirection()
233                     != View.LAYOUT_DIRECTION_RTL) {
234                 return;
235             }
236             LinearLayout linearLayout = (LinearLayout) group;
237             if (linearLayout.getOrientation() == LinearLayout.VERTICAL) {
238                 int childCount = linearLayout.getChildCount();
239                 ArrayList<View> childList = new ArrayList<>(childCount);
240                 for (int i = 0; i < childCount; i++) {
241                     childList.add(linearLayout.getChildAt(i));
242                 }
243                 linearLayout.removeAllViews();
244                 for (int i = childCount - 1; i >= 0; i--) {
245                     linearLayout.addView(childList.get(i));
246                 }
247             }
248         }
249 
250         @Override
onDetachedFromWindow()251         public void onDetachedFromWindow() {
252             mContext.unregisterReceiver(mReceiver);
253         }
254 
onConfigurationChanged()255         protected void onConfigurationChanged() {
256             removeAllViews();
257             inflateView(isLandscapePhone(mContext));
258         }
259 
260         private final Runnable mUpdateLayoutRunnable = new Runnable() {
261             @Override
262             public void run() {
263                 if (mLayout != null && mLayout.getParent() != null) {
264                     mLayout.setLayoutParams(getRequestLayoutParams(isLandscapePhone(mContext)));
265                 }
266             }
267         };
268 
269         private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
270             @Override
271             public void onReceive(Context context, Intent intent) {
272                 if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
273                     post(mUpdateLayoutRunnable);
274                 } else if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)
275                         || intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
276                     clearPrompt();
277                 }
278             }
279         };
280     }
281 
282 }
283