1*90c8c64dSAndroid Build Coastguard Worker /* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2015 Google Inc. All Rights Reserved. 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker package com.example.android.wearable.wear.alwayson; 17*90c8c64dSAndroid Build Coastguard Worker 18*90c8c64dSAndroid Build Coastguard Worker import android.app.AlarmManager; 19*90c8c64dSAndroid Build Coastguard Worker import android.app.PendingIntent; 20*90c8c64dSAndroid Build Coastguard Worker import android.content.Context; 21*90c8c64dSAndroid Build Coastguard Worker import android.content.Intent; 22*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Color; 23*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle; 24*90c8c64dSAndroid Build Coastguard Worker import android.os.Handler; 25*90c8c64dSAndroid Build Coastguard Worker import android.os.Message; 26*90c8c64dSAndroid Build Coastguard Worker import android.support.wearable.activity.WearableActivity; 27*90c8c64dSAndroid Build Coastguard Worker import android.support.wearable.view.WatchViewStub; 28*90c8c64dSAndroid Build Coastguard Worker import android.util.Log; 29*90c8c64dSAndroid Build Coastguard Worker import android.widget.TextView; 30*90c8c64dSAndroid Build Coastguard Worker 31*90c8c64dSAndroid Build Coastguard Worker import java.lang.ref.WeakReference; 32*90c8c64dSAndroid Build Coastguard Worker import java.text.SimpleDateFormat; 33*90c8c64dSAndroid Build Coastguard Worker import java.util.Date; 34*90c8c64dSAndroid Build Coastguard Worker import java.util.Locale; 35*90c8c64dSAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit; 36*90c8c64dSAndroid Build Coastguard Worker 37*90c8c64dSAndroid Build Coastguard Worker /** 38*90c8c64dSAndroid Build Coastguard Worker * Demonstrates support for Ambient screens by extending WearableActivity and overriding 39*90c8c64dSAndroid Build Coastguard Worker * onEnterAmbient, onUpdateAmbient, and onExitAmbient. 40*90c8c64dSAndroid Build Coastguard Worker * 41*90c8c64dSAndroid Build Coastguard Worker * There are two modes (Active and Ambient). To trigger future updates (data/screen), we use a 42*90c8c64dSAndroid Build Coastguard Worker * custom Handler for the "Active" mode and an Alarm for the "Ambient" mode. 43*90c8c64dSAndroid Build Coastguard Worker * 44*90c8c64dSAndroid Build Coastguard Worker * Why don't we use just one? Handlers are generally less battery intensive and can be triggered 45*90c8c64dSAndroid Build Coastguard Worker * every second. However, they can not wake up the processor (common in Ambient mode). 46*90c8c64dSAndroid Build Coastguard Worker * 47*90c8c64dSAndroid Build Coastguard Worker * Alarms can wake up the processor (what we need for Ambient), but they struggle with quick updates 48*90c8c64dSAndroid Build Coastguard Worker * (less than one second) and are much less efficient compared to Handlers. 49*90c8c64dSAndroid Build Coastguard Worker * 50*90c8c64dSAndroid Build Coastguard Worker * Therefore, we use Handlers for "Active" mode (can trigger every second and are better on the 51*90c8c64dSAndroid Build Coastguard Worker * battery), and we use Alarms for "Ambient" mode (only need to update once every 20 seconds and 52*90c8c64dSAndroid Build Coastguard Worker * they can wake up a sleeping processor). 53*90c8c64dSAndroid Build Coastguard Worker * 54*90c8c64dSAndroid Build Coastguard Worker * Again, the Activity waits 20 seconds between doing any processing (getting data, updating screen 55*90c8c64dSAndroid Build Coastguard Worker * etc.) while in ambient mode to conserving battery life (processor allowed to sleep). If you can 56*90c8c64dSAndroid Build Coastguard Worker * hold off on updates for a full minute, you can throw away all the Alarm code and just use 57*90c8c64dSAndroid Build Coastguard Worker * onUpdateAmbient() to save even more battery life. 58*90c8c64dSAndroid Build Coastguard Worker * 59*90c8c64dSAndroid Build Coastguard Worker * As always, you will still want to apply the performance guidelines outlined in the Watch Faces 60*90c8c64dSAndroid Build Coastguard Worker * documention to your app. 61*90c8c64dSAndroid Build Coastguard Worker * 62*90c8c64dSAndroid Build Coastguard Worker * Finally, in ambient mode, this Activity follows the same best practices outlined in the 63*90c8c64dSAndroid Build Coastguard Worker * Watch Faces API documentation, e.g., keep most pixels black, avoid large blocks of white pixels, 64*90c8c64dSAndroid Build Coastguard Worker * use only black and white, and disable anti-aliasing. 65*90c8c64dSAndroid Build Coastguard Worker * 66*90c8c64dSAndroid Build Coastguard Worker */ 67*90c8c64dSAndroid Build Coastguard Worker public class MainActivity extends WearableActivity { 68*90c8c64dSAndroid Build Coastguard Worker 69*90c8c64dSAndroid Build Coastguard Worker private static final String TAG = "MainActivity"; 70*90c8c64dSAndroid Build Coastguard Worker 71*90c8c64dSAndroid Build Coastguard Worker /** Custom 'what' for Message sent to Handler. */ 72*90c8c64dSAndroid Build Coastguard Worker private static final int MSG_UPDATE_SCREEN = 0; 73*90c8c64dSAndroid Build Coastguard Worker 74*90c8c64dSAndroid Build Coastguard Worker /** Milliseconds between updates based on state. */ 75*90c8c64dSAndroid Build Coastguard Worker private static final long ACTIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(1); 76*90c8c64dSAndroid Build Coastguard Worker private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20); 77*90c8c64dSAndroid Build Coastguard Worker 78*90c8c64dSAndroid Build Coastguard Worker /** Tracks latest ambient details, such as burnin offsets, etc. */ 79*90c8c64dSAndroid Build Coastguard Worker private Bundle mAmbientDetails; 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker private TextView mTimeTextView; 82*90c8c64dSAndroid Build Coastguard Worker private TextView mTimeStampTextView; 83*90c8c64dSAndroid Build Coastguard Worker private TextView mStateTextView; 84*90c8c64dSAndroid Build Coastguard Worker private TextView mUpdateRateTextView; 85*90c8c64dSAndroid Build Coastguard Worker private TextView mDrawCountTextView; 86*90c8c64dSAndroid Build Coastguard Worker 87*90c8c64dSAndroid Build Coastguard Worker private final SimpleDateFormat sDateFormat = 88*90c8c64dSAndroid Build Coastguard Worker new SimpleDateFormat("HH:mm:ss", Locale.US); 89*90c8c64dSAndroid Build Coastguard Worker 90*90c8c64dSAndroid Build Coastguard Worker private volatile int mDrawCount = 0; 91*90c8c64dSAndroid Build Coastguard Worker 92*90c8c64dSAndroid Build Coastguard Worker 93*90c8c64dSAndroid Build Coastguard Worker /** 94*90c8c64dSAndroid Build Coastguard Worker * Since the handler (used in active mode) can't wake up the processor when the device is in 95*90c8c64dSAndroid Build Coastguard Worker * ambient mode and undocked, we use an Alarm to cover ambient mode updates when we need them 96*90c8c64dSAndroid Build Coastguard Worker * more frequently than every minute. Remember, if getting updates once a minute in ambient 97*90c8c64dSAndroid Build Coastguard Worker * mode is enough, you can do away with the Alarm code and just rely on the onUpdateAmbient() 98*90c8c64dSAndroid Build Coastguard Worker * callback. 99*90c8c64dSAndroid Build Coastguard Worker */ 100*90c8c64dSAndroid Build Coastguard Worker private AlarmManager mAmbientStateAlarmManager; 101*90c8c64dSAndroid Build Coastguard Worker private PendingIntent mAmbientStatePendingIntent; 102*90c8c64dSAndroid Build Coastguard Worker 103*90c8c64dSAndroid Build Coastguard Worker /** 104*90c8c64dSAndroid Build Coastguard Worker * This custom handler is used for updates in "Active" mode. We use a separate static class to 105*90c8c64dSAndroid Build Coastguard Worker * help us avoid memory leaks. 106*90c8c64dSAndroid Build Coastguard Worker */ 107*90c8c64dSAndroid Build Coastguard Worker private final Handler mActiveModeUpdateHandler = new UpdateHandler(this); 108*90c8c64dSAndroid Build Coastguard Worker 109*90c8c64dSAndroid Build Coastguard Worker @Override onCreate(Bundle savedInstanceState)110*90c8c64dSAndroid Build Coastguard Worker public void onCreate(Bundle savedInstanceState) { 111*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onCreate()"); 112*90c8c64dSAndroid Build Coastguard Worker super.onCreate(savedInstanceState); 113*90c8c64dSAndroid Build Coastguard Worker 114*90c8c64dSAndroid Build Coastguard Worker setContentView(R.layout.activity_main); 115*90c8c64dSAndroid Build Coastguard Worker 116*90c8c64dSAndroid Build Coastguard Worker setAmbientEnabled(); 117*90c8c64dSAndroid Build Coastguard Worker 118*90c8c64dSAndroid Build Coastguard Worker mAmbientStateAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 119*90c8c64dSAndroid Build Coastguard Worker Intent ambientStateIntent = new Intent(getApplicationContext(), MainActivity.class); 120*90c8c64dSAndroid Build Coastguard Worker 121*90c8c64dSAndroid Build Coastguard Worker mAmbientStatePendingIntent = PendingIntent.getActivity( 122*90c8c64dSAndroid Build Coastguard Worker getApplicationContext(), 123*90c8c64dSAndroid Build Coastguard Worker 0 /* requestCode */, 124*90c8c64dSAndroid Build Coastguard Worker ambientStateIntent, 125*90c8c64dSAndroid Build Coastguard Worker PendingIntent.FLAG_UPDATE_CURRENT); 126*90c8c64dSAndroid Build Coastguard Worker 127*90c8c64dSAndroid Build Coastguard Worker 128*90c8c64dSAndroid Build Coastguard Worker /** Determines whether watch is round or square and applies proper view. **/ 129*90c8c64dSAndroid Build Coastguard Worker final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); 130*90c8c64dSAndroid Build Coastguard Worker stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { 131*90c8c64dSAndroid Build Coastguard Worker @Override 132*90c8c64dSAndroid Build Coastguard Worker public void onLayoutInflated(WatchViewStub stub) { 133*90c8c64dSAndroid Build Coastguard Worker 134*90c8c64dSAndroid Build Coastguard Worker mTimeTextView = (TextView) stub.findViewById(R.id.time); 135*90c8c64dSAndroid Build Coastguard Worker mTimeStampTextView = (TextView) stub.findViewById(R.id.time_stamp); 136*90c8c64dSAndroid Build Coastguard Worker mStateTextView = (TextView) stub.findViewById(R.id.state); 137*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView = (TextView) stub.findViewById(R.id.update_rate); 138*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView = (TextView) stub.findViewById(R.id.draw_count); 139*90c8c64dSAndroid Build Coastguard Worker 140*90c8c64dSAndroid Build Coastguard Worker refreshDisplayAndSetNextUpdate(); 141*90c8c64dSAndroid Build Coastguard Worker } 142*90c8c64dSAndroid Build Coastguard Worker }); 143*90c8c64dSAndroid Build Coastguard Worker } 144*90c8c64dSAndroid Build Coastguard Worker 145*90c8c64dSAndroid Build Coastguard Worker /** 146*90c8c64dSAndroid Build Coastguard Worker * This is mostly triggered by the Alarms we set in Ambient mode and informs us we need to 147*90c8c64dSAndroid Build Coastguard Worker * update the screen (and process any data). 148*90c8c64dSAndroid Build Coastguard Worker */ 149*90c8c64dSAndroid Build Coastguard Worker @Override onNewIntent(Intent intent)150*90c8c64dSAndroid Build Coastguard Worker public void onNewIntent(Intent intent) { 151*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onNewIntent(): " + intent); 152*90c8c64dSAndroid Build Coastguard Worker super.onNewIntent(intent); 153*90c8c64dSAndroid Build Coastguard Worker 154*90c8c64dSAndroid Build Coastguard Worker setIntent(intent); 155*90c8c64dSAndroid Build Coastguard Worker 156*90c8c64dSAndroid Build Coastguard Worker refreshDisplayAndSetNextUpdate(); 157*90c8c64dSAndroid Build Coastguard Worker } 158*90c8c64dSAndroid Build Coastguard Worker 159*90c8c64dSAndroid Build Coastguard Worker @Override onDestroy()160*90c8c64dSAndroid Build Coastguard Worker public void onDestroy() { 161*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onDestroy()"); 162*90c8c64dSAndroid Build Coastguard Worker 163*90c8c64dSAndroid Build Coastguard Worker mActiveModeUpdateHandler.removeMessages(MSG_UPDATE_SCREEN); 164*90c8c64dSAndroid Build Coastguard Worker mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent); 165*90c8c64dSAndroid Build Coastguard Worker 166*90c8c64dSAndroid Build Coastguard Worker super.onDestroy(); 167*90c8c64dSAndroid Build Coastguard Worker } 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Worker /** 170*90c8c64dSAndroid Build Coastguard Worker * Prepares UI for Ambient view. 171*90c8c64dSAndroid Build Coastguard Worker */ 172*90c8c64dSAndroid Build Coastguard Worker @Override onEnterAmbient(Bundle ambientDetails)173*90c8c64dSAndroid Build Coastguard Worker public void onEnterAmbient(Bundle ambientDetails) { 174*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onEnterAmbient()"); 175*90c8c64dSAndroid Build Coastguard Worker super.onEnterAmbient(ambientDetails); 176*90c8c64dSAndroid Build Coastguard Worker 177*90c8c64dSAndroid Build Coastguard Worker /** 178*90c8c64dSAndroid Build Coastguard Worker * In this sample, we aren't using the ambient details bundle (EXTRA_BURN_IN_PROTECTION or 179*90c8c64dSAndroid Build Coastguard Worker * EXTRA_LOWBIT_AMBIENT), but if you need them, you can pull them from the local variable 180*90c8c64dSAndroid Build Coastguard Worker * set here. 181*90c8c64dSAndroid Build Coastguard Worker */ 182*90c8c64dSAndroid Build Coastguard Worker mAmbientDetails = ambientDetails; 183*90c8c64dSAndroid Build Coastguard Worker 184*90c8c64dSAndroid Build Coastguard Worker /** Clears Handler queue (only needed for updates in active mode). */ 185*90c8c64dSAndroid Build Coastguard Worker mActiveModeUpdateHandler.removeMessages(MSG_UPDATE_SCREEN); 186*90c8c64dSAndroid Build Coastguard Worker 187*90c8c64dSAndroid Build Coastguard Worker /** 188*90c8c64dSAndroid Build Coastguard Worker * Following best practices outlined in WatchFaces API (keeping most pixels black, 189*90c8c64dSAndroid Build Coastguard Worker * avoiding large blocks of white pixels, using only black and white, 190*90c8c64dSAndroid Build Coastguard Worker * and disabling anti-aliasing anti-aliasing, etc.) 191*90c8c64dSAndroid Build Coastguard Worker */ 192*90c8c64dSAndroid Build Coastguard Worker mStateTextView.setTextColor(Color.WHITE); 193*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.setTextColor(Color.WHITE); 194*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.setTextColor(Color.WHITE); 195*90c8c64dSAndroid Build Coastguard Worker 196*90c8c64dSAndroid Build Coastguard Worker mTimeTextView.getPaint().setAntiAlias(false); 197*90c8c64dSAndroid Build Coastguard Worker mTimeStampTextView.getPaint().setAntiAlias(false); 198*90c8c64dSAndroid Build Coastguard Worker mStateTextView.getPaint().setAntiAlias(false); 199*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.getPaint().setAntiAlias(false); 200*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.getPaint().setAntiAlias(false); 201*90c8c64dSAndroid Build Coastguard Worker 202*90c8c64dSAndroid Build Coastguard Worker refreshDisplayAndSetNextUpdate(); 203*90c8c64dSAndroid Build Coastguard Worker } 204*90c8c64dSAndroid Build Coastguard Worker 205*90c8c64dSAndroid Build Coastguard Worker /** 206*90c8c64dSAndroid Build Coastguard Worker * Updates UI in Ambient view (once a minute). Because we need to update UI sooner than that 207*90c8c64dSAndroid Build Coastguard Worker * (every ~20 seconds), we also use an Alarm. However, since the processor is awake for this 208*90c8c64dSAndroid Build Coastguard Worker * callback, we might as well call refreshDisplayAndSetNextUpdate() to update screen and reset 209*90c8c64dSAndroid Build Coastguard Worker * the Alarm. 210*90c8c64dSAndroid Build Coastguard Worker * 211*90c8c64dSAndroid Build Coastguard Worker * If you are happy with just updating the screen once a minute in Ambient Mode (which will be 212*90c8c64dSAndroid Build Coastguard Worker * the case a majority of the time), then you can just use this method and remove all 213*90c8c64dSAndroid Build Coastguard Worker * references/code regarding Alarms. 214*90c8c64dSAndroid Build Coastguard Worker */ 215*90c8c64dSAndroid Build Coastguard Worker @Override onUpdateAmbient()216*90c8c64dSAndroid Build Coastguard Worker public void onUpdateAmbient() { 217*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onUpdateAmbient()"); 218*90c8c64dSAndroid Build Coastguard Worker super.onUpdateAmbient(); 219*90c8c64dSAndroid Build Coastguard Worker 220*90c8c64dSAndroid Build Coastguard Worker refreshDisplayAndSetNextUpdate(); 221*90c8c64dSAndroid Build Coastguard Worker } 222*90c8c64dSAndroid Build Coastguard Worker 223*90c8c64dSAndroid Build Coastguard Worker /** 224*90c8c64dSAndroid Build Coastguard Worker * Prepares UI for Active view (non-Ambient). 225*90c8c64dSAndroid Build Coastguard Worker */ 226*90c8c64dSAndroid Build Coastguard Worker @Override onExitAmbient()227*90c8c64dSAndroid Build Coastguard Worker public void onExitAmbient() { 228*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "onExitAmbient()"); 229*90c8c64dSAndroid Build Coastguard Worker super.onExitAmbient(); 230*90c8c64dSAndroid Build Coastguard Worker 231*90c8c64dSAndroid Build Coastguard Worker /** Clears out Alarms since they are only used in ambient mode. */ 232*90c8c64dSAndroid Build Coastguard Worker mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent); 233*90c8c64dSAndroid Build Coastguard Worker 234*90c8c64dSAndroid Build Coastguard Worker mStateTextView.setTextColor(Color.GREEN); 235*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.setTextColor(Color.GREEN); 236*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.setTextColor(Color.GREEN); 237*90c8c64dSAndroid Build Coastguard Worker 238*90c8c64dSAndroid Build Coastguard Worker mTimeTextView.getPaint().setAntiAlias(true); 239*90c8c64dSAndroid Build Coastguard Worker mTimeStampTextView.getPaint().setAntiAlias(true); 240*90c8c64dSAndroid Build Coastguard Worker mStateTextView.getPaint().setAntiAlias(true); 241*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.getPaint().setAntiAlias(true); 242*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.getPaint().setAntiAlias(true); 243*90c8c64dSAndroid Build Coastguard Worker 244*90c8c64dSAndroid Build Coastguard Worker refreshDisplayAndSetNextUpdate(); 245*90c8c64dSAndroid Build Coastguard Worker } 246*90c8c64dSAndroid Build Coastguard Worker 247*90c8c64dSAndroid Build Coastguard Worker /** 248*90c8c64dSAndroid Build Coastguard Worker * Loads data/updates screen (via method), but most importantly, sets up the next refresh 249*90c8c64dSAndroid Build Coastguard Worker * (active mode = Handler and ambient mode = Alarm). 250*90c8c64dSAndroid Build Coastguard Worker */ refreshDisplayAndSetNextUpdate()251*90c8c64dSAndroid Build Coastguard Worker private void refreshDisplayAndSetNextUpdate() { 252*90c8c64dSAndroid Build Coastguard Worker 253*90c8c64dSAndroid Build Coastguard Worker loadDataAndUpdateScreen(); 254*90c8c64dSAndroid Build Coastguard Worker 255*90c8c64dSAndroid Build Coastguard Worker long timeMs = System.currentTimeMillis(); 256*90c8c64dSAndroid Build Coastguard Worker 257*90c8c64dSAndroid Build Coastguard Worker if (isAmbient()) { 258*90c8c64dSAndroid Build Coastguard Worker /** Calculate next trigger time (based on state). */ 259*90c8c64dSAndroid Build Coastguard Worker long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS); 260*90c8c64dSAndroid Build Coastguard Worker long triggerTimeMs = timeMs + delayMs; 261*90c8c64dSAndroid Build Coastguard Worker 262*90c8c64dSAndroid Build Coastguard Worker /** 263*90c8c64dSAndroid Build Coastguard Worker * Note: Make sure you have set activity launchMode to singleInstance in the manifest. 264*90c8c64dSAndroid Build Coastguard Worker * Otherwise, it is easy for the AlarmManager launch intent to open a new activity 265*90c8c64dSAndroid Build Coastguard Worker * every time the Alarm is triggered rather than reusing this Activity. 266*90c8c64dSAndroid Build Coastguard Worker */ 267*90c8c64dSAndroid Build Coastguard Worker mAmbientStateAlarmManager.setExact( 268*90c8c64dSAndroid Build Coastguard Worker AlarmManager.RTC_WAKEUP, 269*90c8c64dSAndroid Build Coastguard Worker triggerTimeMs, 270*90c8c64dSAndroid Build Coastguard Worker mAmbientStatePendingIntent); 271*90c8c64dSAndroid Build Coastguard Worker 272*90c8c64dSAndroid Build Coastguard Worker } else { 273*90c8c64dSAndroid Build Coastguard Worker /** Calculate next trigger time (based on state). */ 274*90c8c64dSAndroid Build Coastguard Worker long delayMs = ACTIVE_INTERVAL_MS - (timeMs % ACTIVE_INTERVAL_MS); 275*90c8c64dSAndroid Build Coastguard Worker 276*90c8c64dSAndroid Build Coastguard Worker mActiveModeUpdateHandler.removeMessages(MSG_UPDATE_SCREEN); 277*90c8c64dSAndroid Build Coastguard Worker mActiveModeUpdateHandler.sendEmptyMessageDelayed(MSG_UPDATE_SCREEN, delayMs); 278*90c8c64dSAndroid Build Coastguard Worker } 279*90c8c64dSAndroid Build Coastguard Worker } 280*90c8c64dSAndroid Build Coastguard Worker 281*90c8c64dSAndroid Build Coastguard Worker /** 282*90c8c64dSAndroid Build Coastguard Worker * Updates display based on Ambient state. If you need to pull data, you should do it here. 283*90c8c64dSAndroid Build Coastguard Worker */ loadDataAndUpdateScreen()284*90c8c64dSAndroid Build Coastguard Worker private void loadDataAndUpdateScreen() { 285*90c8c64dSAndroid Build Coastguard Worker 286*90c8c64dSAndroid Build Coastguard Worker mDrawCount += 1; 287*90c8c64dSAndroid Build Coastguard Worker long currentTimeMs = System.currentTimeMillis(); 288*90c8c64dSAndroid Build Coastguard Worker Log.d(TAG, "loadDataAndUpdateScreen(): " + currentTimeMs + "(" + isAmbient() + ")"); 289*90c8c64dSAndroid Build Coastguard Worker 290*90c8c64dSAndroid Build Coastguard Worker if (isAmbient()) { 291*90c8c64dSAndroid Build Coastguard Worker 292*90c8c64dSAndroid Build Coastguard Worker mTimeTextView.setText(sDateFormat.format(new Date())); 293*90c8c64dSAndroid Build Coastguard Worker mTimeStampTextView.setText(getString(R.string.timestamp_label, currentTimeMs)); 294*90c8c64dSAndroid Build Coastguard Worker 295*90c8c64dSAndroid Build Coastguard Worker mStateTextView.setText(getString(R.string.mode_ambient_label)); 296*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.setText( 297*90c8c64dSAndroid Build Coastguard Worker getString(R.string.update_rate_label, (AMBIENT_INTERVAL_MS / 1000))); 298*90c8c64dSAndroid Build Coastguard Worker 299*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.setText(getString(R.string.draw_count_label, mDrawCount)); 300*90c8c64dSAndroid Build Coastguard Worker 301*90c8c64dSAndroid Build Coastguard Worker } else { 302*90c8c64dSAndroid Build Coastguard Worker mTimeTextView.setText(sDateFormat.format(new Date())); 303*90c8c64dSAndroid Build Coastguard Worker mTimeStampTextView.setText(getString(R.string.timestamp_label, currentTimeMs)); 304*90c8c64dSAndroid Build Coastguard Worker 305*90c8c64dSAndroid Build Coastguard Worker mStateTextView.setText(getString(R.string.mode_active_label)); 306*90c8c64dSAndroid Build Coastguard Worker mUpdateRateTextView.setText( 307*90c8c64dSAndroid Build Coastguard Worker getString(R.string.update_rate_label, (ACTIVE_INTERVAL_MS / 1000))); 308*90c8c64dSAndroid Build Coastguard Worker 309*90c8c64dSAndroid Build Coastguard Worker mDrawCountTextView.setText(getString(R.string.draw_count_label, mDrawCount)); 310*90c8c64dSAndroid Build Coastguard Worker } 311*90c8c64dSAndroid Build Coastguard Worker } 312*90c8c64dSAndroid Build Coastguard Worker 313*90c8c64dSAndroid Build Coastguard Worker /** 314*90c8c64dSAndroid Build Coastguard Worker * Handler separated into static class to avoid memory leaks. 315*90c8c64dSAndroid Build Coastguard Worker */ 316*90c8c64dSAndroid Build Coastguard Worker private static class UpdateHandler extends Handler { 317*90c8c64dSAndroid Build Coastguard Worker private final WeakReference<MainActivity> mMainActivityWeakReference; 318*90c8c64dSAndroid Build Coastguard Worker UpdateHandler(MainActivity reference)319*90c8c64dSAndroid Build Coastguard Worker public UpdateHandler(MainActivity reference) { 320*90c8c64dSAndroid Build Coastguard Worker mMainActivityWeakReference = new WeakReference<MainActivity>(reference); 321*90c8c64dSAndroid Build Coastguard Worker } 322*90c8c64dSAndroid Build Coastguard Worker 323*90c8c64dSAndroid Build Coastguard Worker @Override handleMessage(Message message)324*90c8c64dSAndroid Build Coastguard Worker public void handleMessage(Message message) { 325*90c8c64dSAndroid Build Coastguard Worker MainActivity mainActivity = mMainActivityWeakReference.get(); 326*90c8c64dSAndroid Build Coastguard Worker 327*90c8c64dSAndroid Build Coastguard Worker if (mainActivity != null) { 328*90c8c64dSAndroid Build Coastguard Worker switch (message.what) { 329*90c8c64dSAndroid Build Coastguard Worker case MSG_UPDATE_SCREEN: 330*90c8c64dSAndroid Build Coastguard Worker mainActivity.refreshDisplayAndSetNextUpdate(); 331*90c8c64dSAndroid Build Coastguard Worker break; 332*90c8c64dSAndroid Build Coastguard Worker } 333*90c8c64dSAndroid Build Coastguard Worker } 334*90c8c64dSAndroid Build Coastguard Worker } 335*90c8c64dSAndroid Build Coastguard Worker } 336*90c8c64dSAndroid Build Coastguard Worker }