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
17package com.example.android.demomodecontroller;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.graphics.Color;
23import android.graphics.PointF;
24import android.os.Bundle;
25import android.os.Handler;
26import android.os.HandlerThread;
27import android.os.SystemClock;
28import android.util.Log;
29import android.view.MotionEvent;
30import android.view.View;
31import android.view.View.OnTouchListener;
32import android.view.ViewConfiguration;
33import android.view.WindowManager;
34import android.widget.Toast;
35
36public 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
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
74    protected void onPause() {
75        super.onPause();
76        exitDemoMode();
77    }
78
79    @Override
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
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
203    private void toggleMode() {
204        if (DEBUG) Log.d(TAG, "toggleMode");
205        mBarMode = (mBarMode + 1) % 3;
206        updateMode();
207    }
208
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
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
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