DeskClock.java revision fc177987092f72f84f0833f80600d4bbf20d0b87
1/* 2 * Copyright (C) 2009 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.android.deskclock; 18 19import android.app.ActionBar; 20import android.app.ActionBar.Tab; 21import android.app.Activity; 22import android.app.Fragment; 23import android.app.FragmentTransaction; 24import android.content.ActivityNotFoundException; 25import android.content.Context; 26import android.content.Intent; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.Message; 30import android.support.v13.app.FragmentPagerAdapter; 31import android.support.v4.view.ViewPager; 32import android.util.Log; 33import android.view.Menu; 34import android.view.MenuItem; 35import android.view.View; 36import android.view.animation.AnimationUtils; 37import android.widget.PopupMenu; 38import android.widget.Toast; 39 40import com.android.deskclock.timer.TimerFragment; 41 42import java.util.ArrayList; 43 44/** 45 * DeskClock clock view for desk docks. 46 */ 47public class DeskClock extends Activity { 48 private static final boolean DEBUG = false; 49 50 private static final String LOG_TAG = "DeskClock"; 51 52 // Alarm action for midnight (so we can update the date display). 53 private static final String KEY_SELECTED_TAB = "selected_tab"; 54 private static final String KEY_CLOCK_STATE = "clock_state"; 55 56 public static final String SELECT_TAB_INTENT_EXTRA = "deskclock.select.tab"; 57 58 private ActionBar mActionBar; 59 private Tab mTimerTab; 60 private Tab mClockTab; 61 private Tab mStopwatchTab; 62 63 private ViewPager mViewPager; 64 private TabsAdapter mTabsAdapter; 65 66 public static final int TIMER_TAB_INDEX = 0; 67 public static final int CLOCK_TAB_INDEX = 1; 68 public static final int STOPWATCH_TAB_INDEX = 2; 69 70 private int mSelectedTab; 71 private final boolean mDimmed = false; 72 73 private int mClockState = CLOCK_NORMAL; 74 private static final int CLOCK_NORMAL = 0; 75 private static final int CLOCK_LIGHTS_OUT = 1; 76 private static final int CLOCK_DIMMED = 2; 77 78 79 80 // Delay before hiding the action bar and buttons 81 private static final long LIGHTSOUT_TIMEOUT = 10 * 1000; // 10 seconds 82 // Delay before dimming the screen 83 private static final long DIM_TIMEOUT = 10 * 1000; // 10 seconds 84 85 // Opacity of black layer between clock display and wallpaper. 86 private final float DIM_BEHIND_AMOUNT_NORMAL = 0.4f; 87 private final float DIM_BEHIND_AMOUNT_DIMMED = 0.8f; // higher contrast when display dimmed 88 89 private final int SCREEN_SAVER_TIMEOUT_MSG = 0x2000; 90 private final int SCREEN_SAVER_MOVE_MSG = 0x2001; 91 private final int DIM_TIMEOUT_MSG = 0x2002; 92 private final int LIGHTSOUT_TIMEOUT_MSG = 0x2003; 93 private final int BACK_TO_NORMAL_MSG = 0x2004; 94 95 96 97 private final Handler mHandy = new Handler() { 98 @Override 99 public void handleMessage(Message m) { 100 /* if (m.what == LIGHTSOUT_TIMEOUT_MSG) { 101 doLightsOut(true); 102 mClockState = CLOCK_LIGHTS_OUT; 103 // Only dim if clock fragment is visible 104 if (mViewPager.getCurrentItem() == CLOCK_TAB_INDEX) { 105 scheduleDim(); 106 } 107 } else if (m.what == DIM_TIMEOUT_MSG) { 108 mClockState = CLOCK_DIMMED; 109 doDim(true); 110 } else if (m.what == BACK_TO_NORMAL_MSG){ 111 // ignore user interaction and do not go back to normal if a button was clicked 112 DeskClockFragment f = 113 (DeskClockFragment) mTabsAdapter.getFragment(mViewPager.getCurrentItem()); 114 if (f != null && f.isButtonClicked()) { 115 return; 116 } 117 118 int oldState = mClockState; 119 mClockState = CLOCK_NORMAL; 120 121 switch (oldState) { 122 case CLOCK_LIGHTS_OUT: 123 doLightsOut(false); 124 break; 125 case CLOCK_DIMMED: 126 doLightsOut(false); 127 doDim(true); 128 break; 129 } 130 }*/ 131 } 132 }; 133 134 @Override 135 public void onNewIntent(Intent newIntent) { 136 super.onNewIntent(newIntent); 137 if (DEBUG) Log.d(LOG_TAG, "onNewIntent with intent: " + newIntent); 138 139 // update our intent so that we can consult it to determine whether or 140 // not the most recent launch was via a dock event 141 setIntent(newIntent); 142 143 // Timer receiver may ask to go to the timers fragment if a timer expired. 144 int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1); 145 if (tab != -1) { 146 if (mActionBar != null) { 147 mActionBar.setSelectedNavigationItem(tab); 148 } 149 } 150 } 151 152 private void initViews() { 153 154 if (mTabsAdapter == null) { 155 mViewPager = new ViewPager(this); 156 mViewPager.setId(R.id.desk_clock_pager); 157 mTabsAdapter = new TabsAdapter(this, mViewPager); 158 createTabs(mSelectedTab); 159 } 160 setContentView(mViewPager); 161 mActionBar.setSelectedNavigationItem(mSelectedTab); 162 } 163 164 private void createTabs(int selectedIndex) { 165 mActionBar = getActionBar(); 166 167 mActionBar.setDisplayOptions(0); 168 if (mActionBar != null) { 169 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 170 mTimerTab = mActionBar.newTab(); 171 mTimerTab.setIcon(R.drawable.timer_tab); 172 mTabsAdapter.addTab(mTimerTab, TimerFragment.class,TIMER_TAB_INDEX); 173 174 mClockTab = mActionBar.newTab(); 175 mClockTab.setIcon(R.drawable.clock_tab); 176 mTabsAdapter.addTab(mClockTab, ClockFragment.class,CLOCK_TAB_INDEX); 177 mStopwatchTab = mActionBar.newTab(); 178 mStopwatchTab.setIcon(R.drawable.stopwatch_tab); 179 mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class,STOPWATCH_TAB_INDEX); 180 mActionBar.setSelectedNavigationItem(selectedIndex); 181 } 182 } 183 184 @Override 185 protected void onCreate(Bundle icicle) { 186 super.onCreate(icicle); 187 188 mSelectedTab = CLOCK_TAB_INDEX; 189 if (icicle != null) { 190 mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX); 191 mClockState = icicle.getInt(KEY_CLOCK_STATE, CLOCK_NORMAL); 192 } 193 194 // Timer receiver may ask the app to go to the timer fragment if a timer expired 195 Intent i = getIntent(); 196 if (i != null) { 197 int tab = i.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1); 198 if (tab != -1) { 199 mSelectedTab = tab; 200 } 201 } 202 initViews(); 203 } 204 205 @Override 206 protected void onResume() { 207 super.onResume(); 208 setClockState(false); 209 } 210 211 @Override 212 public void onPause() { 213 super.onPause(); 214 } 215 216 @Override 217 protected void onSaveInstanceState(Bundle outState) { 218 super.onSaveInstanceState(outState); 219 outState.putInt(KEY_SELECTED_TAB, mActionBar.getSelectedNavigationIndex()); 220 outState.putInt(KEY_CLOCK_STATE, mClockState); 221 } 222 223 private void setClockState(boolean fade) { 224 doDim(fade); 225 switch(mClockState) { 226 case CLOCK_NORMAL: 227 doLightsOut(false); 228 break; 229 case CLOCK_LIGHTS_OUT: 230 case CLOCK_DIMMED: 231 doLightsOut(true); 232 break; 233 default: 234 break; 235 } 236 } 237 238 public void clockButtonsOnClick(View v) { 239 if (v == null) 240 return; 241 switch (v.getId()) { 242 case R.id.alarms_button: 243 startActivity(new Intent(this, AlarmClock.class)); 244 break; 245 case R.id.cities_button: 246 Toast.makeText(this, "Not implemented yet", 2).show(); 247 break; 248 case R.id.menu_button: 249 showMenu(v); 250 break; 251 default: 252 break; 253 } 254 } 255 256 private void showMenu(View v) { 257 PopupMenu popupMenu = new PopupMenu(this, v); 258 popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener () { 259 @Override 260 public boolean onMenuItemClick(MenuItem item) { 261 switch (item.getItemId()) { 262 case R.id.menu_item_settings: 263 startActivity(new Intent(DeskClock.this, SettingsActivity.class)); 264 return true; 265 case R.id.menu_item_help: 266 Intent i = item.getIntent(); 267 if (i != null) { 268 try { 269 startActivity(i); 270 } catch (ActivityNotFoundException e) { 271 // No activity found to match the intent - ignore 272 } 273 } 274 return true; 275 default: 276 break; 277 } 278 return true; 279 } 280 }); 281 popupMenu.inflate(R.menu.desk_clock_menu); 282 283 Menu menu = popupMenu.getMenu(); 284 MenuItem help = menu.findItem(R.id.menu_item_help); 285 if (help != null) { 286 Utils.prepareHelpMenuItem(this, help); 287 } 288 popupMenu.show(); 289 } 290 291 private void scheduleLightsOut() { 292 mHandy.removeMessages(LIGHTSOUT_TIMEOUT_MSG); 293 mHandy.sendMessageDelayed(Message.obtain(mHandy, LIGHTSOUT_TIMEOUT_MSG), LIGHTSOUT_TIMEOUT); 294 } 295 296 public void doLightsOut(boolean state) { 297 298 if (state) { 299 mViewPager.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); 300 mActionBar.hide(); 301 } else { 302 mViewPager.setSystemUiVisibility(View.STATUS_BAR_VISIBLE); 303 mActionBar.show(); 304 } 305 306 // in clock view show/hide the buttons at the bottom 307 if (mViewPager.getCurrentItem() == CLOCK_TAB_INDEX) { 308 // TODO: switch to listeners 309/* Fragment f = mTabsAdapter.getFragment(CLOCK_TAB_INDEX); 310 if (f != null) { 311 ((ClockFragment)f).showButtons(!state); 312 }*/ 313 } 314 if (!state) { 315 // Make sure dim will not start before lights out 316 mHandy.removeMessages(DIM_TIMEOUT_MSG); 317 scheduleLightsOut(); 318 } 319 } 320 321 private void doDim(boolean fade) { 322 if (mClockState == CLOCK_DIMMED) { 323 mViewPager.startAnimation( 324 AnimationUtils.loadAnimation(this, fade ? R.anim.dim : R.anim.dim_instant)); 325 } else { 326 mViewPager.startAnimation( 327 AnimationUtils.loadAnimation(this, fade ? R.anim.undim : R.anim.undim_instant)); 328 } 329 } 330 331 private void scheduleDim() { 332 mHandy.removeMessages(DIM_TIMEOUT_MSG); 333 mHandy.sendMessageDelayed(Message.obtain(mHandy, DIM_TIMEOUT_MSG), DIM_TIMEOUT); 334 } 335 336 @Override 337 public void onUserInteraction() { 338 super.onUserInteraction(); 339 mHandy.removeMessages(BACK_TO_NORMAL_MSG); 340 mHandy.sendMessage(Message.obtain(mHandy, BACK_TO_NORMAL_MSG)); 341 } 342 343 /*** 344 * Adapter for wrapping together the ActionBar's tab with the ViewPager 345 */ 346 347 private class TabsAdapter extends FragmentPagerAdapter 348 implements ActionBar.TabListener, ViewPager.OnPageChangeListener { 349 350 private static final String KEY_TAB_POSITION = "tab_position"; 351 352 final class TabInfo { 353 private final Class<?> clss; 354 private final Bundle args; 355 356 TabInfo(Class<?> _class, int position) { 357 clss = _class; 358 args = new Bundle(); 359 args.putInt(KEY_TAB_POSITION, position); 360 } 361 362 public int getPosition() { 363 return args.getInt(KEY_TAB_POSITION, 0); 364 } 365 } 366 367 private final ArrayList<TabInfo> mTabs = new ArrayList <TabInfo>(); 368 ActionBar mMainActionBar; 369 Context mContext; 370 ViewPager mPager; 371 372 public TabsAdapter(Activity activity, ViewPager pager) { 373 super(activity.getFragmentManager()); 374 mContext = activity; 375 mMainActionBar = activity.getActionBar(); 376 mPager = pager; 377 mPager.setAdapter(this); 378 mPager.setOnPageChangeListener(this); 379 } 380 381 @Override 382 public Fragment getItem(int position) { 383 TabInfo info = mTabs.get(position); 384 DeskClockFragment f = (DeskClockFragment) Fragment.instantiate( 385 mContext, info.clss.getName(), info.args); 386 return f; 387 } 388 389 @Override 390 public int getCount() { 391 return mTabs.size(); 392 } 393 394 public void addTab(ActionBar.Tab tab, Class<?> clss, int position) { 395 TabInfo info = new TabInfo(clss, position); 396 tab.setTag(info); 397 tab.setTabListener(this); 398 mTabs.add(info); 399 mMainActionBar.addTab(tab); 400 notifyDataSetChanged(); 401 } 402 403 @Override 404 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 405 // Do nothing 406 } 407 408 @Override 409 public void onPageSelected(int position) { 410 mMainActionBar.setSelectedNavigationItem(position); 411 onUserInteraction(); 412 } 413 414 @Override 415 public void onPageScrollStateChanged(int state) { 416 // Do nothing 417 } 418 419 @Override 420 public void onTabReselected(Tab arg0, FragmentTransaction arg1) { 421 // Do nothing 422 } 423 424 @Override 425 public void onTabSelected(Tab tab, FragmentTransaction ft) { 426 TabInfo info = (TabInfo)tab.getTag(); 427 mPager.setCurrentItem(info.getPosition()); 428 onUserInteraction(); 429 } 430 431 @Override 432 public void onTabUnselected(Tab arg0, FragmentTransaction arg1) { 433 // Do nothing 434 435 } 436 } 437} 438