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.example.android.demomodecontroller;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.graphics.Color;
23 import android.graphics.PointF;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 import android.os.SystemClock;
28 import android.util.Log;
29 import android.view.MotionEvent;
30 import android.view.View;
31 import android.view.View.OnTouchListener;
32 import android.view.ViewConfiguration;
33 import android.view.WindowManager;
34 import android.widget.Toast;
35 
36 public class DemoModeController extends Activity implements OnTouchListener {
37     private static final String TAG = DemoModeController.class.getSimpleName();
38     private static final boolean DEBUG = false;
39 
40     private final Context mContext = this;
41     private final Handler mHandler = new Handler();
42     private final PointF mLastDown = new PointF();
43 
44     private View mContent;
45     private Handler mBackground;
46     private int mTouchSlop;
47     private long mLastDownTime;
48     private boolean mControllingColor;
49     private Toast mToast;
50 
51     @Override
onCreate(Bundle savedInstanceState)52     protected void onCreate(Bundle savedInstanceState) {
53         super.onCreate(savedInstanceState);
54         getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
55                 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS  // so WM gives us enough room
56                 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
57         getActionBar().hide();
58         mContent = new View(mContext);
59         mContent.setBackgroundColor(0xff33b5e5);
60         mContent.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
61                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
62                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
63         mContent.setOnTouchListener(this);
64         setContentView(mContent);
65         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
66 
67         final HandlerThread background = new HandlerThread("background");
68         background.start();
69         mBackground = new Handler(background.getLooper());
70         updateMode();
71     }
72 
73     @Override
onPause()74     protected void onPause() {
75         super.onPause();
76         exitDemoMode();
77     }
78 
79     @Override
onResume()80     protected void onResume() {
81         super.onResume();
82         exitDemoMode();
83         mToast = Toast.makeText(mContext, R.string.help_text, Toast.LENGTH_LONG);
84         mToast.show();
85     }
86 
87     @Override
onTouch(View v, MotionEvent event)88     public boolean onTouch(View v, MotionEvent event) {
89         if (mToast != null) {
90             mToast.cancel();
91             mToast = null;
92         }
93         final int action = event.getAction();
94         if (action == MotionEvent.ACTION_DOWN) {
95             if (DEBUG) Log.d(TAG, "down");
96             mHandler.postDelayed(mLongPressCheck, 500);
97             final long now = SystemClock.uptimeMillis();
98             if (now - mLastDownTime < 200) {
99                 toggleMode();
100             }
101             mLastDownTime = now;
102             mLastDown.x = event.getX();
103             mLastDown.y = event.getY();
104             return true;
105         }
106         if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
107             if (DEBUG) Log.d(TAG, "upOrCancel");
108             mControllingColor = false;
109             mHandler.removeCallbacks(mLongPressCheck);
110         }
111         if (action != MotionEvent.ACTION_MOVE) return false;
112 
113         float x = event.getX();
114         float y = event.getY();
115         if (Math.abs(mLastDown.x - x) > mTouchSlop || Math.abs(mLastDown.y - y) > mTouchSlop) {
116             mHandler.removeCallbacks(mLongPressCheck);
117         }
118         x = Math.max(x, 0);
119         y = Math.max(y, 0);
120         final int h = mContent.getMeasuredHeight();
121         final int w = mContent.getMeasuredWidth();
122         x = Math.min(x, w);
123         y = Math.min(y, h);
124 
125         y = h - y;
126         x = w - x;
127 
128         if (mControllingColor) {
129             final float hue = y / (h / 360);
130             final float sat = 1 - (x / (float)w);
131             final float val = x / (float)w;
132             final int color = Color.HSVToColor(new float[]{hue, sat, val});
133             if (DEBUG) Log.d(TAG, String.format("hsv=(%s,%s,%s) argb=#%08x", hue, sat, val, color));
134             mContent.setBackgroundColor(color);
135             return true;
136         }
137 
138         final int hh = (int)x / (w / 12);
139         if (hh != mHH) {
140             mHH = hh;
141             mBackground.removeCallbacks(mUpdateClock);
142             mBackground.post(mUpdateClock);
143         }
144 
145         final int mm = (int)y / (h / 60);
146         if (mm != mMM) {
147             mMM = mm;
148             mBackground.removeCallbacks(mUpdateClock);
149             mBackground.post(mUpdateClock);
150         }
151 
152         final int batteryLevel = (int)y / (h / 101);
153         if (batteryLevel != mBatteryLevel) {
154             mBatteryLevel = batteryLevel;
155             mBackground.removeCallbacks(mUpdateBattery);
156             mBackground.post(mUpdateBattery);
157         }
158 
159         final boolean batteryPlugged = x >= w / 2;
160         if (batteryPlugged != mBatteryPlugged) {
161             mBatteryPlugged = batteryPlugged;
162             mBackground.removeCallbacks(mUpdateBattery);
163             mBackground.post(mUpdateBattery);
164         }
165 
166         final int mobileLevel = (int)y / (h / 10);
167         if (mobileLevel != mMobileLevel) {
168             mMobileLevel = mobileLevel;
169             mBackground.removeCallbacks(mUpdateMobile);
170             mBackground.post(mUpdateMobile);
171         }
172 
173         final int wifiLevel = (int)y / (h / 10);
174         if (wifiLevel != mWifiLevel) {
175             mWifiLevel = wifiLevel;
176             mBackground.removeCallbacks(mUpdateWifi);
177             mBackground.post(mUpdateWifi);
178         }
179 
180         final int statusSlots = (int)x / (w / 13);
181         if (statusSlots != mStatusSlots) {
182             mStatusSlots = statusSlots;
183             mBackground.removeCallbacks(mUpdateStatus);
184             mBackground.post(mUpdateStatus);
185         }
186 
187         final int networkIcons = (int)x / (w / 4);
188         if (networkIcons != mNetworkIcons) {
189             mNetworkIcons = networkIcons;
190             mBackground.removeCallbacks(mUpdateNetwork);
191             mBackground.post(mUpdateNetwork);
192         }
193 
194         final int mobileDataType = (int)y / (h / 9);
195         if (mobileDataType != mMobileDataType) {
196             mMobileDataType = mobileDataType;
197             mBackground.removeCallbacks(mUpdateMobile);
198             mBackground.post(mUpdateMobile);
199         }
200         return true;
201     }
202 
toggleMode()203     private void toggleMode() {
204         if (DEBUG) Log.d(TAG, "toggleMode");
205         mBarMode = (mBarMode + 1) % 3;
206         updateMode();
207     }
208 
updateMode()209     private void updateMode() {
210         mBackground.removeCallbacks(mUpdateBarMode);
211         mBackground.post(mUpdateBarMode);
212     }
213 
214     private final Runnable mLongPressCheck = new Runnable() {
215         @Override
216         public void run() {
217             if (DEBUG) Log.d(TAG, "mControllingColor = true");
218             mControllingColor = true;
219 
220         }
221     };
222 
exitDemoMode()223     private void exitDemoMode() {
224         if (DEBUG) Log.d(TAG, "exitDemoMode");
225         final Intent intent = new Intent("com.android.systemui.demo");
226         intent.putExtra("command", "exit");
227         mContext.sendBroadcast(intent);
228     }
229 
230     private int mStatusSlots; // 0 - 12
231     private final Runnable mUpdateStatus = new Runnable() {
232         @Override
233         public void run() {
234             final Intent intent = new Intent("com.android.systemui.demo");
235             intent.putExtra("command", "status");
236             intent.putExtra("volume", mStatusSlots < 1 ? "hide"
237                     : mStatusSlots < 2 ? "silent" : "vibrate");
238             intent.putExtra("bluetooth", mStatusSlots < 3 ? "hide"
239                     : mStatusSlots < 4 ? "disconnected" : "connected");
240             intent.putExtra("location", mStatusSlots < 5 ? "hide" : "show");
241             intent.putExtra("alarm", mStatusSlots < 6 ? "hide" : "show");
242             intent.putExtra("sync", mStatusSlots < 7 ? "hide" : "show");
243             intent.putExtra("tty", mStatusSlots < 8 ? "hide" : "show");
244             intent.putExtra("eri", mStatusSlots < 9 ? "hide" : "show");
245             intent.putExtra("secure", mStatusSlots < 10 ? "hide" : "show");
246             intent.putExtra("mute", mStatusSlots < 11 ? "hide" : "show");
247             intent.putExtra("speakerphone", mStatusSlots < 12 ? "hide" : "show");
248             mContext.sendBroadcast(intent);
249         }
250     };
251 
252     private int mNetworkIcons;  // 0:airplane  1:mobile  2:airplane+wifi  3:mobile+wifi
253     private final Runnable mUpdateNetwork = new Runnable() {
254         @Override
255         public void run() {
256             final Intent intent = new Intent("com.android.systemui.demo");
257             intent.putExtra("command", "network");
258             intent.putExtra("airplane", mNetworkIcons % 2 == 0 ? "show" : "hide");
259             intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
260             intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
261             mContext.sendBroadcast(intent);
262         }
263     };
264 
265     private int mWifiLevel; // 0 - 4, 5 - 9, fully
266     private final Runnable mUpdateWifi = new Runnable() {
267         @Override
268         public void run() {
269             final Intent intent = new Intent("com.android.systemui.demo");
270             intent.putExtra("command", "network");
271             intent.putExtra("wifi", mNetworkIcons >= 2 ? "show" : "hide");
272             intent.putExtra("level", Integer.toString(mWifiLevel % 5));
273             intent.putExtra("fully", Boolean.toString(mWifiLevel > 4));
274             mContext.sendBroadcast(intent);
275         }
276     };
277 
278     private int mMobileLevel; // 0 - 4, 5 - 9, fully
279     private int mMobileDataType; // 0 - 8
getDataType(int dataType)280     private static final String getDataType(int dataType) {
281         if (dataType == 1) return "1x";
282         if (dataType == 2) return "3g";
283         if (dataType == 3) return "4g";
284         if (dataType == 4) return "e";
285         if (dataType == 5) return "g";
286         if (dataType == 6) return "h";
287         if (dataType == 7) return "lte";
288         if (dataType == 8) return "roam";
289         return "";
290     }
291     private final Runnable mUpdateMobile = new Runnable() {
292         @Override
293         public void run() {
294             final Intent intent = new Intent("com.android.systemui.demo");
295             intent.putExtra("command", "network");
296             intent.putExtra("mobile", mNetworkIcons % 2 == 1 ? "show" : "hide");
297             intent.putExtra("level", Integer.toString(mMobileLevel % 5));
298             intent.putExtra("fully", Boolean.toString(mMobileLevel > 4));
299             intent.putExtra("datatype", getDataType(mMobileDataType));
300             mContext.sendBroadcast(intent);
301         }
302     };
303 
304     private boolean mBatteryPlugged;
305     private int mBatteryLevel; // 0 - 100
306     private final Runnable mUpdateBattery = new Runnable() {
307         @Override
308         public void run() {
309             final Intent intent = new Intent("com.android.systemui.demo");
310             intent.putExtra("command", "battery");
311             intent.putExtra("level", Integer.toString(mBatteryLevel));
312             intent.putExtra("plugged", Boolean.toString(mBatteryPlugged));
313             mContext.sendBroadcast(intent);
314         }
315     };
316 
317     private int mHH; // 0 - 11
318     private int mMM; // 0 - 59
319     private final Runnable mUpdateClock = new Runnable() {
320         @Override
321         public void run() {
322             final Intent intent = new Intent("com.android.systemui.demo");
323             intent.putExtra("command", "clock");
324             intent.putExtra("hhmm", String.format("%02d%02d", mHH + 1, mMM));
325             mContext.sendBroadcast(intent);
326         }
327     };
328 
329     private int mBarMode; // 0 - 2  (opaque, semi-transparent, translucent)
330     private final Runnable mUpdateBarMode = new Runnable() {
331         @Override
332         public void run() {
333             final Intent intent = new Intent("com.android.systemui.demo");
334             intent.putExtra("command", "bars");
335             intent.putExtra("mode", mBarMode == 1 ? "semi-transparent"
336                     : mBarMode == 2 ? "translucent" : "opaque");
337             mContext.sendBroadcast(intent);
338         }
339     };
340 }
341