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