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