Fix snooze event tracking
am: e5cf47c18e
* commit 'e5cf47c18e3588b12beb2a01b9d1d0c816e4868c':
Fix snooze event tracking
diff --git a/.gitignore b/.gitignore
index cece67b..c6cbe56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,18 +1,8 @@
-.classpath
-.gitignore
-.gradle
-.idea
-.name
-.project
-bin
-build
-gen
-lint.xml
-local.properties
-out
-project.properties
-*.DS_Store
-*~
*.iml
-*.swo
-*.swp
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
diff --git a/Android.mk b/Android.mk
index a8e5217..906dab8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,13 +6,17 @@
ifeq ($(TARGET_BUILD_APPS),)
LOCAL_RESOURCE_DIR += frameworks/support/design/res
+LOCAL_RESOURCE_DIR += frameworks/support/v14/preference/res
LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
LOCAL_RESOURCE_DIR += frameworks/support/v7/gridlayout/res
+LOCAL_RESOURCE_DIR += frameworks/support/v7/preference/res
LOCAL_RESOURCE_DIR += frameworks/support/v7/recyclerview/res
else
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/design/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v14/preference/res
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/gridlayout/res
+LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/preference/res
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/recyclerview/res
endif
@@ -25,19 +29,21 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src gen)
LOCAL_STATIC_JAVA_LIBRARIES := android-opt-datetimepicker
-LOCAL_STATIC_JAVA_LIBRARIES += messageformat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v14-preference
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-gridlayout
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-preference
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages android.support.design
+LOCAL_AAPT_FLAGS += --extra-packages android.support.v14.preference
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.gridlayout
+LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.preference
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.recyclerview
LOCAL_AAPT_FLAGS += --extra-packages com.android.datetimepicker
-LOCAL_AAPT_FLAGS += --extra-packages com.android.messageformat
include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 441ad87..8500c85 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,9 +15,12 @@
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.deskclock"
- android:versionCode="410" android:versionName="4.1.0">
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.deskclock"
+ android:versionCode="440"
+ android:versionName="4.4.0">
<original-package android:name="com.android.alarmclock" />
<original-package android:name="com.android.deskclock" />
@@ -25,8 +28,8 @@
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- <uses-permission android:name="android.permission.WAKE_LOCK"/>
- <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- WRITE_SETTINGS is required to record the upcoming alarm prior to L -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
@@ -35,26 +38,28 @@
<!-- READ_EXTERNAL_STORAGE is required to play custom ringtones from the SD card prior to M -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <application android:label="@string/app_label"
- android:name=".DeskClockApplication"
- android:allowBackup="true"
- android:backupAgent="DeskClockBackupAgent"
- android:fullBackupContent="@xml/backup_scheme"
- android:fullBackupOnly="true"
- android:icon="@mipmap/ic_launcher_alarmclock"
- android:requiredForAllUsers="true"
- android:supportsRtl="true">
+ <application
+ android:name=".DeskClockApplication"
+ android:allowBackup="true"
+ android:backupAgent="DeskClockBackupAgent"
+ android:fullBackupContent="@xml/backup_scheme"
+ android:fullBackupOnly="true"
+ android:icon="@mipmap/ic_launcher_alarmclock"
+ android:label="@string/app_label"
+ android:requiredForAllUsers="true"
+ android:supportsRtl="true">
- <provider android:name=".provider.ClockProvider"
- android:authorities="com.android.deskclock"
- android:exported="false" />
+ <provider
+ android:name=".provider.ClockProvider"
+ android:authorities="com.android.deskclock"
+ android:exported="false" />
- <activity android:name="DeskClock"
- android:label="@string/app_label"
- android:theme="@style/DeskClockTheme"
- android:icon="@mipmap/ic_launcher_alarmclock"
- android:launchMode="singleTask">
-
+ <activity
+ android:name=".DeskClock"
+ android:icon="@mipmap/ic_launcher_alarmclock"
+ android:label="@string/app_label"
+ android:launchMode="singleTask"
+ android:theme="@style/DeskClockTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -62,14 +67,14 @@
</intent-filter>
</activity>
- <activity-alias android:name="DockClock"
- android:targetActivity="DeskClock"
- android:label="@string/app_label"
- android:theme="@style/DeskClockTheme"
- android:icon="@mipmap/ic_launcher_alarmclock"
- android:launchMode="singleTask"
- android:enabled="@bool/config_dockAppEnabled"
- >
+ <activity-alias
+ android:name=".DockClock"
+ android:enabled="false"
+ android:icon="@mipmap/ic_launcher_alarmclock"
+ android:label="@string/app_label"
+ android:launchMode="singleTask"
+ android:targetActivity="DeskClock"
+ android:theme="@style/DeskClockTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -77,54 +82,58 @@
</intent-filter>
</activity-alias>
- <activity android:name=".settings.SettingsActivity"
- android:label="@string/settings"
- android:theme="@style/SettingsTheme"
- android:taskAffinity=""
- android:excludeFromRecents="true"
- >
+ <activity
+ android:name=".settings.SettingsActivity"
+ android:excludeFromRecents="true"
+ android:label="@string/settings"
+ android:taskAffinity=""
+ android:theme="@style/SettingsTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
- <activity android:name=".worldclock.CitySelectionActivity"
- android:label="@string/cities_activity_title"
- android:theme="@style/CitiesTheme"
- android:taskAffinity=""
- android:excludeFromRecents="true">
+ <activity
+ android:name=".worldclock.CitySelectionActivity"
+ android:excludeFromRecents="true"
+ android:label="@string/cities_activity_title"
+ android:taskAffinity=""
+ android:theme="@style/CitiesTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
- <activity android:name=".alarms.AlarmActivity"
- android:taskAffinity=""
- android:excludeFromRecents="true"
- android:theme="@style/AlarmAlertFullScreenTheme"
- android:windowSoftInputMode="stateAlwaysHidden"
- android:showOnLockScreen="true" />
+ <activity
+ android:name=".alarms.AlarmActivity"
+ android:excludeFromRecents="true"
+ android:showOnLockScreen="true"
+ android:taskAffinity=""
+ android:theme="@style/AlarmAlertFullScreenTheme"
+ android:windowSoftInputMode="stateAlwaysHidden" />
- <activity android:name="ScreensaverActivity"
- android:excludeFromRecents="true"
- android:taskAffinity=""
- android:theme="@style/ScreensaverActivityTheme"
- android:configChanges="orientation|screenSize|keyboardHidden|keyboard" />
+ <activity
+ android:name=".ScreensaverActivity"
+ android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
+ android:excludeFromRecents="true"
+ android:taskAffinity=""
+ android:theme="@style/ScreensaverActivityTheme" />
- <receiver android:name=".alarms.AlarmStateManager"
- android:exported="false">
- </receiver>
+ <receiver
+ android:name=".alarms.AlarmStateManager"
+ android:exported="false" />
- <service android:name=".alarms.AlarmService"
- android:exported="false">
- </service>
+ <service
+ android:name=".alarms.AlarmService"
+ android:exported="false" />
- <activity android:name="HandleApiCalls"
- android:theme="@android:style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:launchMode="singleTask"
- android:permission="com.android.alarm.permission.SET_ALARM"
- android:taskAffinity="">
+ <activity
+ android:name=".HandleApiCalls"
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:permission="com.android.alarm.permission.SET_ALARM"
+ android:taskAffinity=""
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.SET_ALARM" />
<category android:name="android.intent.category.DEFAULT" />
@@ -152,17 +161,18 @@
</intent-filter>
</activity>
- <activity-alias android:name="HandleSetAlarm"
- android:targetActivity=".HandleApiCalls"
- android:exported="true">
- </activity-alias>
+ <activity-alias
+ android:name="HandleSetAlarm"
+ android:exported="true"
+ android:targetActivity=".HandleApiCalls" />
- <activity android:name=".HandleDeskClockApiCalls"
- android:theme="@android:style/Theme.NoDisplay"
+ <activity
+ android:name=".HandleDeskClockApiCalls"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:permission="com.android.alarm.permission.SET_ALARM"
- android:taskAffinity="">
+ android:taskAffinity=""
+ android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="com.android.deskclock.action.SHOW_CLOCK" />
<category android:name="android.intent.category.DEFAULT" />
@@ -230,7 +240,7 @@
</intent-filter>
</activity>
- <receiver android:name="AlarmInitReceiver">
+ <receiver android:name=".AlarmInitReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.TIME_SET" />
@@ -245,15 +255,15 @@
android:icon="@mipmap/ic_launcher_alarmclock"
android:label="@string/analog_gadget">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.oldName"
- android:value="com.android.deskclock.AnalogAppWidgetProvider"/>
+ android:value="com.android.deskclock.AnalogAppWidgetProvider" />
<meta-data
android:name="android.appwidget.provider"
- android:resource="@xml/analog_appwidget"/>
+ android:resource="@xml/analog_appwidget" />
</receiver>
<receiver
@@ -261,27 +271,29 @@
android:icon="@mipmap/ic_launcher_alarmclock"
android:label="@string/digital_gadget">
<intent-filter>
- <action android:name="android.intent.action.TIME_SET"/>
- <action android:name="android.intent.action.SCREEN_ON"/>
- <action android:name="android.intent.action.DATE_CHANGED"/>
- <action android:name="android.intent.action.LOCALE_CHANGED"/>
- <action android:name="android.intent.action.TIMEZONE_CHANGED"/>
- <action android:name="com.android.deskclock.DIGITAL_WIDGET_CHANGED"/>
- <action android:name="com.android.deskclock.ON_QUARTER_HOUR"/>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
- <action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED"/>
+ <action android:name="android.intent.action.TIME_SET" />
+ <action android:name="android.intent.action.SCREEN_ON" />
+ <action android:name="android.intent.action.DATE_CHANGED" />
+ <action android:name="android.intent.action.LOCALE_CHANGED" />
+ <action android:name="android.intent.action.TIMEZONE_CHANGED" />
+ <action android:name="com.android.deskclock.DIGITAL_WIDGET_CHANGED" />
+ <action android:name="com.android.deskclock.ON_QUARTER_HOUR" />
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ <action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
- android:resource="@xml/digital_appwidget"/>
+ android:resource="@xml/digital_appwidget" />
</receiver>
- <service android:name="com.android.alarmclock.DigitalAppWidgetService"
- android:permission="android.permission.BIND_REMOTEVIEWS"
- android:exported="false" />
+ <service
+ android:name="com.android.alarmclock.DigitalAppWidgetService"
+ android:exported="false"
+ android:permission="android.permission.BIND_REMOTEVIEWS" />
<!-- Dream (screensaver) implementation -->
- <service android:name="Screensaver"
+ <service
+ android:name=".Screensaver"
android:exported="true"
android:label="@string/app_label"
android:permission="android.permission.BIND_DREAM_SERVICE">
@@ -296,13 +308,13 @@
</service>
<!-- Settings activity for screensaver -->
- <activity android:name=".settings.ScreensaverSettingsActivity"
- android:label="@string/screensaver_settings"
- android:theme="@style/SettingsTheme"
- android:taskAffinity=""
- android:excludeFromRecents="true"
- android:exported="true"
- >
+ <activity
+ android:name=".settings.ScreensaverSettingsActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:label="@string/screensaver_settings"
+ android:taskAffinity=""
+ android:theme="@style/SettingsTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
@@ -311,18 +323,19 @@
<activity
android:name=".AlarmSelectionActivity"
android:label="@string/dismiss_alarm"
- android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar"/>
+ android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar" />
<!-- This activity displays only the timers that have expired with only a reset button
present. This makes the activity appropriate for display above the lock screen so that
users have the limited ability to silence expired timers but nothing else. -->
- <activity android:name=".timer.ExpiredTimersActivity"
- android:excludeFromRecents="true"
- android:theme="@style/ExpiredTimersActivityTheme"
- android:launchMode="singleInstance"
- android:showOnLockScreen="true"
- android:taskAffinity=""
- android:configChanges="screenSize|keyboardHidden|keyboard|navigation"/>
+ <activity
+ android:name=".timer.ExpiredTimersActivity"
+ android:configChanges="screenSize|keyboardHidden|keyboard|navigation"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:showOnLockScreen="true"
+ android:taskAffinity=""
+ android:theme="@style/ExpiredTimersActivityTheme" />
<!-- Legacy broadcast receiver that honors old scheduled timers across app upgrade. -->
<receiver android:name="com.android.deskclock.timer.TimerReceiver"
@@ -332,14 +345,17 @@
</intent-filter>
</receiver>
- <service android:name=".timer.TimerService"
- android:exported="false"
- android:description="@string/timer_service_desc">
- </service>
+ <service
+ android:name=".timer.TimerService"
+ android:description="@string/timer_service_desc"
+ android:exported="false"
+ tools:ignore="ManifestResource" />
- <service android:name=".stopwatch.StopwatchService"
- android:exported="false"
- android:description="@string/stopwatch_service_desc">
- </service>
+ <service
+ android:name=".stopwatch.StopwatchService"
+ android:description="@string/stopwatch_service_desc"
+ android:exported="false"
+ tools:ignore="ManifestResource" />
+
</application>
</manifest>
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index aa37742..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-* Copyright (C) 2015 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-apply plugin: "com.android.application"
-
-android {
- sourceSets {
- main {
- manifest.srcFile "AndroidManifest.xml"
- java.srcDir "src"
- res.srcDir "res"
- assets.srcDir "assets"
- }
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_7
- targetCompatibility JavaVersion.VERSION_1_7
- }
-
- dependencies {
- compile (project(":android-opt-datetimepicker")) {
- exclude module: "support-v4"
- }
- compile project(":messageformat")
- compile project(":support-design")
- compile project(":support-v7-appcompat")
- compile project(":support-v7-gridlayout")
- compile project(":support-v7-recyclerview")
- compile project(":support-v13")
- }
-}
diff --git a/gen/com/android/deskclock/BuildConfig.java b/gen/com/android/deskclock/BuildConfig.java
index 861848f..c88f182 100644
--- a/gen/com/android/deskclock/BuildConfig.java
+++ b/gen/com/android/deskclock/BuildConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/res/color-v23/timepicker_ampm.xml b/res/color-v23/timepicker_ampm.xml
deleted file mode 100644
index df92405..0000000
--- a/res/color-v23/timepicker_ampm.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_selected="true"
- android:color="@color/white" />
- <item
- android:alpha="?android:attr/disabledAlpha"
- android:color="@color/white" />
-</selector>
diff --git a/res/color-v23/timepicker_time.xml b/res/color-v23/timepicker_time.xml
deleted file mode 100644
index 100473c..0000000
--- a/res/color-v23/timepicker_time.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_selected="true"
- android:color="?android:attr/colorAccent" />
- <item android:color="@color/white" />
-</selector>
\ No newline at end of file
diff --git a/res/drawable-v21/fastscroll_preview_left.xml b/res/drawable-v21/fastscroll_preview_left.xml
deleted file mode 100644
index 51e54ea..0000000
--- a/res/drawable-v21/fastscroll_preview_left.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/fastscroll_preview_padding">
- <shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners
- android:topLeftRadius="44dp"
- android:topRightRadius="44dp"
- android:bottomRightRadius="44dp" />
- <padding
- android:paddingLeft="22dp"
- android:paddingRight="22dp" />
- <solid android:color="@color/color_accent" />
- </shape>
-</inset>
diff --git a/res/drawable-v21/fastscroll_preview_right.xml b/res/drawable-v21/fastscroll_preview_right.xml
deleted file mode 100644
index c2dff95..0000000
--- a/res/drawable-v21/fastscroll_preview_right.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetRight="@dimen/fastscroll_preview_padding">
- <shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners
- android:topLeftRadius="44dp"
- android:topRightRadius="44dp"
- android:bottomLeftRadius="44dp" />
- <padding
- android:paddingLeft="22dp"
- android:paddingRight="22dp" />
- <solid android:color="@color/color_accent" />
- </shape>
-</inset>
diff --git a/res/drawable/fastscroll_track.xml b/res/drawable/fastscroll_track.xml
index 2057c5b..81b6261 100644
--- a/res/drawable/fastscroll_track.xml
+++ b/res/drawable/fastscroll_track.xml
@@ -19,13 +19,13 @@
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#1fffffff"/>
- <size android:width="@dimen/fastscroll_thumb_width" />
+ <size android:width="@dimen/fastscroll_track_width" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/transparent"/>
- <size android:width="@dimen/fastscroll_thumb_width" />
+ <size android:width="@dimen/fastscroll_track_width" />
</shape>
</item>
</selector>
diff --git a/res/layout-land/time_setup_view.xml b/res/layout-land/time_setup_view.xml
index b5e68e1..c59b4a4 100644
--- a/res/layout-land/time_setup_view.xml
+++ b/res/layout-land/time_setup_view.xml
@@ -13,81 +13,74 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:orientation="horizontal">
+ <!-- This nested ltr layout cannot be combined with the parent because
+ in RTL, the Keypad and Timer value should swap. -->
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/timer_time_display"
+ android:layout_width="0dip"
android:layout_height="match_parent"
- android:baselineAligned="false"
- android:orientation="horizontal">
+ android:layout_weight="3"
+ android:layout_marginBottom="@dimen/footer_button_size"
+ android:layoutDirection="ltr"
+ android:gravity="center"
+ android:orientation="vertical">
- <!-- This nested ltr layout cannot be combined with the parent because
- in RTL, the Keypad and Timer value should swap. -->
- <LinearLayout
- android:id="@+id/timer_time_display"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="3"
- android:layout_marginBottom="@dimen/footer_button_size"
- android:layoutDirection="ltr"
- android:gravity="center"
- android:orientation="vertical">
+ <com.android.deskclock.timer.TimerView
+ android:id="@+id/timer_time_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
- <com.android.deskclock.timer.TimerView
- android:id="@+id/timer_time_text"
+ <include layout="@layout/timer_h_mm_ss_view" />
+
+ <ImageButton
+ android:id="@+id/delete"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical">
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:layout_marginStart="@dimen/timer_setup_delete_start_margin"
+ android:padding="@dimen/timer_setup_delete_padding"
+ android:contentDescription="@string/timer_delete"
+ android:scaleType="center"
+ android:src="@drawable/ic_backspace" />
- <include layout="@layout/timer_h_mm_ss_view" />
+ </com.android.deskclock.timer.TimerView>
- <ImageButton
- android:id="@+id/delete"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:layout_marginStart="@dimen/timer_setup_delete_start_margin"
- android:padding="@dimen/timer_setup_delete_padding"
- android:contentDescription="@string/timer_delete"
- android:scaleType="center"
- android:src="@drawable/ic_backspace" />
-
- </com.android.deskclock.timer.TimerView>
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_marginBottom="8dip"
- android:background="@color/dialog_gray" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="2"
- android:orientation="vertical" >
-
- <include
- android:id="@+id/first"
- layout="@layout/three_keys_view" />
- <include
- android:id="@+id/second"
- layout="@layout/three_keys_view" />
- <include
- android:id="@+id/third"
- layout="@layout/three_keys_view" />
- <include
- android:id="@+id/fourth"
- layout="@layout/three_keys_view" />
-
- </LinearLayout>
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginBottom="8dip"
+ android:background="@color/dialog_gray" />
</LinearLayout>
- <include layout="@layout/timer_setup_buttons" />
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="2"
+ android:orientation="vertical">
-</FrameLayout>
\ No newline at end of file
+ <include
+ android:id="@+id/first"
+ layout="@layout/three_keys_view" />
+ <include
+ android:id="@+id/second"
+ layout="@layout/three_keys_view" />
+ <include
+ android:id="@+id/third"
+ layout="@layout/three_keys_view" />
+ <include
+ android:id="@+id/fourth"
+ layout="@layout/three_keys_view" />
+
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout-land/world_clock_item.xml b/res/layout-land/world_clock_item.xml
index c2a7a6a..ac56a79 100644
--- a/res/layout-land/world_clock_item.xml
+++ b/res/layout-land/world_clock_item.xml
@@ -62,7 +62,6 @@
android:id="@+id/city_name_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:layout_marginLeft="@dimen/label_margin_small"
android:layout_marginStart="@dimen/label_margin_small"
android:gravity="center" >
@@ -72,4 +71,4 @@
</LinearLayout>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/res/layout/alarm_muted_button.xml b/res/layout/alarm_muted_button.xml
new file mode 100644
index 0000000..e9f4aa2
--- /dev/null
+++ b/res/layout/alarm_muted_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<Button
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/alarm_muted_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/tall_row_height"
+ android:background="?attr/selectableItemBackground"
+ android:drawablePadding="@dimen/alarm_horizontal_padding"
+ android:drawableStart="@drawable/ic_alarm_off_24dp"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="@dimen/icon_margin"
+ android:paddingStart="@dimen/icon_margin"
+ android:textAllCaps="false"
+ android:textColor="@color/clock_gray"
+ android:textSize="@dimen/alarm_text_font_size" />
\ No newline at end of file
diff --git a/res/layout/alarm_time_collapsed.xml b/res/layout/alarm_time_collapsed.xml
index 516cff3..736eaa1 100644
--- a/res/layout/alarm_time_collapsed.xml
+++ b/res/layout/alarm_time_collapsed.xml
@@ -31,15 +31,6 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom">
- <View
- android:id="@+id/hairline"
- android:layout_width="match_parent"
- android:layout_height="@dimen/hairline_height"
- android:layout_gravity="bottom"
- android:layout_marginEnd="@dimen/icon_margin"
- android:layout_marginStart="@dimen/icon_margin"
- android:background="@color/hairline" />
-
<com.android.deskclock.widget.EllipsizeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -52,8 +43,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="none"
- android:paddingStart="@dimen/icon_margin"
android:paddingEnd="@dimen/icon_margin"
+ android:paddingStart="@dimen/icon_margin"
android:singleLine="true"
android:textColor="@color/clock_gray"
android:textSize="@dimen/alarm_text_font_size" />
@@ -64,6 +55,8 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:focusable="true"
+ android:paddingEnd="@dimen/icon_margin"
+ android:paddingStart="@dimen/icon_margin"
android:singleLine="true"
android:textColor="@color/clock_white"
android:textSize="@dimen/alarm_text_font_size"
@@ -75,6 +68,8 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:focusable="true"
+ android:paddingEnd="@dimen/icon_margin"
+ android:paddingStart="@dimen/icon_margin"
android:singleLine="true"
android:textColor="@color/clock_white"
android:textSize="@dimen/alarm_text_font_size"
@@ -87,14 +82,23 @@
android:layout_width="@dimen/touch_target_min_size"
android:layout_height="@dimen/touch_target_min_size"
android:layout_gravity="center_vertical|end"
+ android:background="?attr/selectableItemBackground"
android:contentDescription="@string/expand_alarm"
android:scaleType="center"
android:src="@drawable/ic_expand_down" />
</FrameLayout>
- <include
- android:id="@+id/preemptive_dismiss_container"
- layout="@layout/preemptive_dismiss" />
+ <include layout="@layout/alarm_muted_button" />
+ <include layout="@layout/preemptive_dismiss" />
+
+ <View
+ android:id="@+id/hairline"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/hairline_height"
+ android:layout_gravity="bottom"
+ android:layout_marginEnd="@dimen/icon_margin"
+ android:layout_marginStart="@dimen/icon_margin"
+ android:background="@color/hairline" />
</LinearLayout>
diff --git a/res/layout/alarm_time_expanded.xml b/res/layout/alarm_time_expanded.xml
index 38d24de..35e8f6a 100644
--- a/res/layout/alarm_time_expanded.xml
+++ b/res/layout/alarm_time_expanded.xml
@@ -87,6 +87,7 @@
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:includeFontPadding="false"
+ android:paddingEnd="12dp"
android:paddingStart="@dimen/alarm_horizontal_padding"
android:text="@string/alarm_vibrate"
android:textColor="@color/white"
@@ -94,6 +95,8 @@
</LinearLayout>
+ <include layout="@layout/alarm_muted_button" />
+
<TextView
android:id="@+id/edit_label"
android:layout_width="match_parent"
@@ -115,9 +118,7 @@
android:layout_marginStart="@dimen/hairline_side_padding"
android:background="@color/hairline" />
- <include
- android:id="@+id/preemptive_dismiss_container"
- layout="@layout/preemptive_dismiss" />
+ <include layout="@layout/preemptive_dismiss" />
</LinearLayout>
@@ -127,7 +128,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom|start">
- <Button
+ <ImageButton
android:id="@+id/delete"
android:layout_width="@dimen/touch_target_min_size"
android:layout_height="@dimen/tall_row_height"
@@ -136,16 +137,15 @@
android:layout_marginBottom="@dimen/alarm_clock_vertical_margin"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/delete_alarm"
- android:drawableStart="@drawable/ic_delete_small"
- android:drawablePadding="@dimen/alarm_horizontal_padding"
- android:gravity="start|center_vertical"
- android:scaleType="fitStart" />
+ android:scaleType="center"
+ android:src="@drawable/ic_delete_small"/>
<ImageButton
android:id="@+id/arrow"
android:layout_width="@dimen/touch_target_min_size"
android:layout_height="@dimen/touch_target_min_size"
android:layout_gravity="center_vertical|end"
+ android:background="?attr/selectableItemBackground"
android:contentDescription="@string/collapse_alarm"
android:rotation="@integer/chevron_rotate_180"
android:scaleType="center"
diff --git a/res/layout/alarm_volume_preference.xml b/res/layout/alarm_volume_preference.xml
new file mode 100644
index 0000000..be2ae80
--- /dev/null
+++ b/res/layout/alarm_volume_preference.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:orientation="vertical"
+ android:paddingBottom="16dp"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingTop="16dp">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp">
+
+ <ImageView
+ android:id="@+id/alarm_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <SeekBar
+ android:id="@+id/alarm_volume_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/city_list_item.xml b/res/layout/city_list_item.xml
index a5a6ea8..c0c48a6 100644
--- a/res/layout/city_list_item.xml
+++ b/res/layout/city_list_item.xml
@@ -49,6 +49,6 @@
android:id="@+id/city_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="8dip"
+ android:layout_marginEnd="8dip"
android:textAppearance="@style/SecondaryLabelTextAppearance" />
</LinearLayout>
diff --git a/res/layout/desk_clock_saver.xml b/res/layout/desk_clock_saver.xml
index 7d3f2f7..0df842d 100644
--- a/res/layout/desk_clock_saver.xml
+++ b/res/layout/desk_clock_saver.xml
@@ -15,8 +15,8 @@
-->
<!-- Special "screen saver mode" with just the time/date on black. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:dc="http://schemas.android.com/apk/res-auto"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
@@ -56,10 +56,7 @@
android:layout_marginBottom="@dimen/bottom_text_spacing_analog"
android:dial="@drawable/clock_analog_dial_mipmap"
android:hand_hour="@drawable/clock_analog_hour_mipmap"
- android:hand_minute="@drawable/clock_analog_minute_mipmap"
- dc:jewelColor="@color/clock_white"
- dc:jewelOffset="23dp"
- dc:jewelRadius="5dp" />
+ android:hand_minute="@drawable/clock_analog_minute_mipmap" />
<LinearLayout
android:layout_width="wrap_content"
@@ -82,7 +79,6 @@
style="@style/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
android:layout_marginStart="8dip"
android:drawablePadding="2dip"
android:drawableStart="@drawable/ic_alarm_small"
diff --git a/res/layout/digital_widget_time.xml b/res/layout/digital_widget_time.xml
index e0250bf..bc15726 100644
--- a/res/layout/digital_widget_time.xml
+++ b/res/layout/digital_widget_time.xml
@@ -14,35 +14,36 @@
limitations under the License.
-->
-<!-- digital clock for the digital widget -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
android:layout_gravity="center"
- android:baselineAligned="false"
android:background="?android:attr/selectableItemBackground"
- >
+ android:baselineAligned="false"
+ android:orientation="vertical">
<TextClock
- android:id="@+id/the_clock"
- android:format12Hour="@string/main_widget_12_hours_format"
- android:format24Hour="@string/clock_24_hours_format"
+ android:id="@+id/clock"
+ style="@style/widget_big_thin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
- style="@style/widget_big_thin"
- android:textColor="@color/clock_white"
android:layout_gravity="center_horizontal|top"
- android:baselineAligned="true"
android:layout_marginBottom="@dimen/bottom_text_spacing_digital"
- />
+ android:baselineAligned="true"
+ android:format12Hour="@string/main_widget_12_hours_format"
+ android:format24Hour="@string/clock_24_hours_format"
+ android:singleLine="true"
+ android:textColor="@color/clock_white" />
+
<LinearLayout
+ android:id="@+id/date_and_alarm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/date_and_alarm"
android:gravity="center">
- <TextClock android:id="@+id/date"
+
+ <TextClock
+ android:id="@+id/date"
style="@style/widget_label"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@@ -50,21 +51,21 @@
android:format12Hour=""
android:format24Hour=""
android:gravity="center"
- android:textColor="@color/clock_white"
- />
+ android:textColor="@color/clock_white" />
+
<TextView
android:id="@+id/nextAlarm"
style="@style/widget_label"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
- android:layout_marginStart="6dp"
- android:drawablePadding="6dp"
+ android:layout_marginStart="@dimen/alarm_icon_padding"
+ android:drawablePadding="@dimen/alarm_icon_padding"
android:ellipsize="end"
android:gravity="center"
android:singleLine="true"
android:textColor="@color/clock_gray"
- android:visibility="gone"
- />
+ android:visibility="gone" />
</LinearLayout>
-</LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/main_clock_frame.xml b/res/layout/main_clock_frame.xml
index 240f21a..60e4191 100644
--- a/res/layout/main_clock_frame.xml
+++ b/res/layout/main_clock_frame.xml
@@ -70,9 +70,8 @@
android:id="@+id/nextAlarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginStart="8dip"
- android:drawablePadding="2dip"
+ android:layout_marginStart="@dimen/alarm_icon_padding"
+ android:drawablePadding="@dimen/alarm_icon_padding"
android:drawableStart="@drawable/ic_alarm_small"
android:textAppearance="@style/SecondaryLabelTextAppearance" />
</LinearLayout>
diff --git a/res/layout/preemptive_dismiss.xml b/res/layout/preemptive_dismiss.xml
index 2a32d7a..91dfdd8 100644
--- a/res/layout/preemptive_dismiss.xml
+++ b/res/layout/preemptive_dismiss.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<LinearLayout
- android:id="@+id/preemptive_dismiss"
+ android:id="@+id/preemptive_dismiss_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/settings.xml b/res/layout/settings.xml
index f587342..8de8357 100644
--- a/res/layout/settings.xml
+++ b/res/layout/settings.xml
@@ -15,14 +15,7 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fitsSystemWindows="true">
-
- <fragment
- android:id="@+id/main"
- android:name="com.android.deskclock.settings.SettingsActivity$PrefsFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</FrameLayout>
+ android:fitsSystemWindows="true" />
diff --git a/res/layout/time_setup_view.xml b/res/layout/time_setup_view.xml
index 7d7bb2c..881b82b 100644
--- a/res/layout/time_setup_view.xml
+++ b/res/layout/time_setup_view.xml
@@ -13,10 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/fab_height">
<com.android.deskclock.timer.TimerView
android:id="@+id/timer_time_text"
@@ -66,6 +68,4 @@
android:id="@+id/fourth"
layout="@layout/three_keys_view" />
- <include layout="@layout/timer_setup_buttons" />
-
</LinearLayout>
diff --git a/res/layout/timer_item.xml b/res/layout/timer_item.xml
index 1d97ecb..6c0a277 100644
--- a/res/layout/timer_item.xml
+++ b/res/layout/timer_item.xml
@@ -50,7 +50,7 @@
android:ellipsize="end"
android:gravity="center"
android:hint="@string/label"
- android:singleLine="true"
+ android:maxLines="1"
android:src="@drawable/ic_label"
android:textAppearance="@style/SecondaryLabelTextAppearance"/>
diff --git a/res/layout/timer_setup_buttons.xml b/res/layout/timer_setup_buttons.xml
deleted file mode 100644
index f0132f2..0000000
--- a/res/layout/timer_setup_buttons.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:orientation="horizontal">
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="start|center_vertical"
- android:layout_weight="1">
-
- <ImageButton
- android:id="@+id/timer_cancel"
- android:layout_width="@dimen/design_fab_size_normal"
- android:layout_height="@dimen/design_fab_size_normal"
- android:layout_gravity="center"
- android:contentDescription="@string/timer_cancel"
- android:scaleType="center"
- android:src="@drawable/ic_cancel" />
-
- </FrameLayout>
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="start|center_vertical"
- android:layout_weight="1">
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/timer_create"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_margin="@dimen/fab_margin"
- android:contentDescription="@string/timer_start"
- android:src="@drawable/ic_start_white_24dp"
- android:visibility="invisible"
- app:borderWidth="0dp"
- app:elevation="@dimen/fab_elevation" />
-
- </FrameLayout>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1" />
-
-</LinearLayout>
diff --git a/res/layout/world_clock_label.xml b/res/layout/world_clock_label.xml
index 360cad1..9111f61 100644
--- a/res/layout/world_clock_label.xml
+++ b/res/layout/world_clock_label.xml
@@ -27,7 +27,6 @@
android:id="@+id/city_day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/style_label_space"
android:layout_marginStart="@dimen/style_label_space"
android:ellipsize="none"
android:singleLine="true"
diff --git a/res/layout/world_clock_remote_list_item.xml b/res/layout/world_clock_remote_list_item.xml
index 6967715..5f585e4 100644
--- a/res/layout/world_clock_remote_list_item.xml
+++ b/res/layout/world_clock_remote_list_item.xml
@@ -61,7 +61,6 @@
style="@style/widget_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/style_label_space"
android:layout_marginStart="@dimen/style_label_space"
android:ellipsize="none"
android:singleLine="true"
@@ -107,7 +106,6 @@
style="@style/widget_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/style_label_space"
android:layout_marginStart="@dimen/style_label_space"
android:ellipsize="none"
android:singleLine="true"
@@ -120,4 +118,4 @@
android:layout_width="match_parent"
android:layout_height="@dimen/digital_widget_city_margin_bottom">
</FrameLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/menu/desk_clock_menu.xml b/res/menu/desk_clock_menu.xml
index 4858714..2bf66c6 100644
--- a/res/menu/desk_clock_menu.xml
+++ b/res/menu/desk_clock_menu.xml
@@ -38,9 +38,5 @@
android:id="@+id/menu_item_settings"
android:icon="@android:drawable/ic_menu_preferences"
android:title="@string/menu_item_settings"/>
- <item
- android:id="@+id/menu_item_help"
- android:icon="@android:drawable/ic_menu_preferences"
- android:title="@string/menu_item_help"/>
</group>
-</menu>
\ No newline at end of file
+</menu>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index df8f2f8..788607e 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibreer"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Herhaal"</string>
<string name="alert" msgid="6506982899651975645">"Alarm se luitoon"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Verstekwekkerklank"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Afteller het verstryk"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Stil"</string>
<string name="ringtone" msgid="9110746249688559579">"Luitoon"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Stede"</string>
<string name="clock_settings" msgid="8317286807280600391">"Horlosie"</string>
<string name="clock_style" msgid="2265011060429742344">"Styl"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Verander datum en tyd"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Verander datum en tyd"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoog"</item>
<item msgid="8483930821046925592">"Digitaal"</item>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 5bf749f..9c34bc0 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ንዘር"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ድገም"</string>
<string name="alert" msgid="6506982899651975645">"የማንቂያ ደውል ቅላጼ"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ነባሪ የማንቂያ ድምጽ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ሰዓት ቆጣሪው ጊዜው አልፏል"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"ፀጥ ያለ"</string>
<string name="ringtone" msgid="9110746249688559579">"የደወል ቅላጼ"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ከተማዎች"</string>
<string name="clock_settings" msgid="8317286807280600391">"ሰዓት"</string>
<string name="clock_style" msgid="2265011060429742344">"ቅጥ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ቀን እና ሰዓት ለውጥ"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ቀን እና ሰዓት ለውጥ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"አናሎግ"</item>
<item msgid="8483930821046925592">"ዲጂታል"</item>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index c70e8bd..aa2df8e 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"اهتزاز"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"تكرار"</string>
<string name="alert" msgid="6506982899651975645">"نغمة رنين المنبه"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"صوت التنبيه الافتراضي"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"انتهت صلاحية الموقِّت"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"صامت"</string>
<string name="ringtone" msgid="9110746249688559579">"نغمة الرنين"</string>
@@ -277,7 +278,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"مدن"</string>
<string name="clock_settings" msgid="8317286807280600391">"الساعة"</string>
<string name="clock_style" msgid="2265011060429742344">"النمط"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"تغيير التاريخ والوقت"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"تغيير التاريخ والوقت"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"تناظري"</item>
<item msgid="8483930821046925592">"رقمي"</item>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 5352482..831d807 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrasiya etdir"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Təkrarla"</string>
<string name="alert" msgid="6506982899651975645">"Siqnalın Zəng səsi"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Defolt siqnal səsi"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Taymerin Vaxtı Bitdi"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Səssiz"</string>
<string name="ringtone" msgid="9110746249688559579">"Zəng səsi"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Şəhərlər"</string>
<string name="clock_settings" msgid="8317286807280600391">"Saat"</string>
<string name="clock_style" msgid="2265011060429742344">"Üslub"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Tarix və vaxtı dəyişin"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Tarix və vaxtı dəyişin"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoq"</item>
<item msgid="8483930821046925592">"Rəqəmsal"</item>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2f879ed..9326ee6 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Вибриране"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Да се повтаря"</string>
<string name="alert" msgid="6506982899651975645">"Мелодия на будилника"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Стандартен звук за будилника"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Изтичане на времето на таймера"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Тих режим"</string>
<string name="ringtone" msgid="9110746249688559579">"Мелодия"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Градове"</string>
<string name="clock_settings" msgid="8317286807280600391">"Часовник"</string>
<string name="clock_style" msgid="2265011060429742344">"Стил"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Промяна на датата и часа"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Промяна на датата и часа"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналогов"</item>
<item msgid="8483930821046925592">"Цифров"</item>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 1ae0afa..2d03b73 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"কম্পন"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"পুনরাবৃত্তি করুন"</string>
<string name="alert" msgid="6506982899651975645">"অ্যালার্ম রিংটোন"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ডিফল্ট অ্যালার্মের শব্দ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"টাইমারের মেয়াদ শেষ হয়ে গেছে"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"নীরব"</string>
<string name="ringtone" msgid="9110746249688559579">"রিংটোন"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"শহর"</string>
<string name="clock_settings" msgid="8317286807280600391">"ঘড়ি"</string>
<string name="clock_style" msgid="2265011060429742344">"শৈলী"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"তারিখ এবং সময় পরিবর্তন করুন"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"তারিখ এবং সময় পরিবর্তন করুন"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"অ্যানালগ"</item>
<item msgid="8483930821046925592">"ডিজিটাল"</item>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 88e5611..b732e13 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibra"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repeteix"</string>
<string name="alert" msgid="6506982899651975645">"So de l\'alarma"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"So d\'alarma predeterminat"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Temporitzador finalitzat"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silenci"</string>
<string name="ringtone" msgid="9110746249688559579">"So"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Ciutats"</string>
<string name="clock_settings" msgid="8317286807280600391">"Rellotge"</string>
<string name="clock_style" msgid="2265011060429742344">"Estil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Canvia la data i l\'hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Canvia la data i l\'hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analògic"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 9b7d80d..81bbb32 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrace"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Opakovat"</string>
<string name="alert" msgid="6506982899651975645">"Vyzváněcí tón budíku"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Výchozí zvuk budíku"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Časovač vypršel"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Tiché"</string>
<string name="ringtone" msgid="9110746249688559579">"Vyzváněcí tón"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Města"</string>
<string name="clock_settings" msgid="8317286807280600391">"Hodiny"</string>
<string name="clock_style" msgid="2265011060429742344">"Styl"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Změnit datum a čas"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Změnit datum a čas"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogové"</item>
<item msgid="8483930821046925592">"Digitální"</item>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 7d26fd0..3d85409 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibration"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Gentag"</string>
<string name="alert" msgid="6506982899651975645">"Ringetone for alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Standardlyd for alarmer"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timeren er udløbet"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Lydløs"</string>
<string name="ringtone" msgid="9110746249688559579">"Ringetone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Byer"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ur"</string>
<string name="clock_style" msgid="2265011060429742344">"Urtype"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Skift dato & klokkeslæt"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Rediger dato og tid"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index b2687a3..e05c846 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrieren"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Wiederholen"</string>
<string name="alert" msgid="6506982899651975645">"Weckton"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Standard-Weckerton"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer abgelaufen"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Lautlos"</string>
<string name="ringtone" msgid="9110746249688559579">"Klingelton"</string>
@@ -218,22 +219,22 @@
<string name="timer_pause" msgid="3748323712728398743">"Pausieren"</string>
<string name="timer_reset_all" msgid="7530633132757866087">"Alle Timer zurücksetzen"</string>
<string-array name="sw_share_strings">
- <item msgid="842841032273927988">"Sie sind teuflisch schnell."</item>
- <item msgid="6332879039890727169">"Ernten Sie die Früchte Ihrer Arbeit!"</item>
- <item msgid="815382761274660130">"Sie sind ja schneller als ein Roboter!"</item>
+ <item msgid="842841032273927988">"Du bist teuflisch schnell."</item>
+ <item msgid="6332879039890727169">"Ernte die Früchte deiner Arbeit!"</item>
+ <item msgid="815382761274660130">"Du bist ja schneller als ein Roboter!"</item>
<item msgid="7916250650982813737">"Puh!"</item>
<item msgid="6836603904515182333">"L33t-Zeiten"</item>
<item msgid="7508085100680861631">"Wahnsinnsgeschwindigkeit"</item>
<item msgid="5961245252909589573">"Let\'s do the time warp again!"</item>
<item msgid="5211891900854545940">"Just a jump to the left."</item>
- <item msgid="9071353477103826053">"Sie haben es ganz schön eilig."</item>
+ <item msgid="9071353477103826053">"Du hast es ganz schön eilig."</item>
<item msgid="3785193933691117181">"Photonengeschwindigkeit"</item>
</string-array>
<string name="home_label" msgid="4436139365695453870">"Zuhause"</string>
<string name="cities_activity_title" msgid="8552462751129256730">"Städte"</string>
<string name="clock_settings" msgid="8317286807280600391">"Uhr"</string>
<string name="clock_style" msgid="2265011060429742344">"Design"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Datum & Uhrzeit ändern"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Datum & Uhrzeit ändern"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index ba757dd..f8d2145 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Δόνηση"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Επανάληψη"</string>
<string name="alert" msgid="6506982899651975645">"Ήχος κλήσης ξυπνητηριού"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Προεπιλεγμένος ήχος ειδοποίησης"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Η αντίστροφη μέτρηση έληξε"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Αθόρυβο"</string>
<string name="ringtone" msgid="9110746249688559579">"Ήχος κλήσης"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Πόλεις"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ρολόι"</string>
<string name="clock_style" msgid="2265011060429742344">"Στυλ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Αλλαγή ημερομηνίας και ώρας"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Αλλαγή ημερομηνίας και ώρας"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Αναλογικό"</item>
<item msgid="8483930821046925592">"Ψηφιακό"</item>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index f6e50f2..21f8b72 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrate"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repeat"</string>
<string name="alert" msgid="6506982899651975645">"Alarm Ringtone"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Default alarm sound"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer Expired"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silent"</string>
<string name="ringtone" msgid="9110746249688559579">"Ring tone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cities"</string>
<string name="clock_settings" msgid="8317286807280600391">"Clock"</string>
<string name="clock_style" msgid="2265011060429742344">"Style"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Change Date & time"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Change date & time"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogue"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index f6e50f2..21f8b72 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrate"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repeat"</string>
<string name="alert" msgid="6506982899651975645">"Alarm Ringtone"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Default alarm sound"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer Expired"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silent"</string>
<string name="ringtone" msgid="9110746249688559579">"Ring tone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cities"</string>
<string name="clock_settings" msgid="8317286807280600391">"Clock"</string>
<string name="clock_style" msgid="2265011060429742344">"Style"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Change Date & time"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Change date & time"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogue"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index f6e50f2..21f8b72 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrate"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repeat"</string>
<string name="alert" msgid="6506982899651975645">"Alarm Ringtone"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Default alarm sound"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer Expired"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silent"</string>
<string name="ringtone" msgid="9110746249688559579">"Ring tone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cities"</string>
<string name="clock_settings" msgid="8317286807280600391">"Clock"</string>
<string name="clock_style" msgid="2265011060429742344">"Style"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Change Date & time"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Change date & time"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogue"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 17fac9e..b445444 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetir"</string>
<string name="alert" msgid="6506982899651975645">"Tono de alarma"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Sonido de alarma predeterminado"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Caducó el temporizador"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencio"</string>
<string name="ringtone" msgid="9110746249688559579">"Tono"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Ciudades"</string>
<string name="clock_settings" msgid="8317286807280600391">"Reloj"</string>
<string name="clock_style" msgid="2265011060429742344">"Estilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Cambiar fecha y hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Cambiar fecha y hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analógico"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 174b996..fe75fc2 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetir"</string>
<string name="alert" msgid="6506982899651975645">"Tono de alarma"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Sonido de alarma predeterminado"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Temporizador agotado"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencio"</string>
<string name="ringtone" msgid="9110746249688559579">"Tono de llamada"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Ciudades"</string>
<string name="clock_settings" msgid="8317286807280600391">"Reloj"</string>
<string name="clock_style" msgid="2265011060429742344">"Estilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Cambiar fecha y hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Cambiar fecha y hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analógico"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 5a4b585..bae67f9 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Värin"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Kordus"</string>
<string name="alert" msgid="6506982899651975645">"Äratuse helin"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Äratuse vaikeheli"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Taimer on aegunud"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Hääletu"</string>
<string name="ringtone" msgid="9110746249688559579">"Helin"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Linnad"</string>
<string name="clock_settings" msgid="8317286807280600391">"Kell"</string>
<string name="clock_style" msgid="2265011060429742344">"Stiil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Kuupäeva ja kellaaja muutmine"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Kuupäeva ja kellaaja muutmine"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoog"</item>
<item msgid="8483930821046925592">"Digitaalne"</item>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 3b5073c..1d2c2eb 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Egin dar-dar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Errepikapena"</string>
<string name="alert" msgid="6506982899651975645">"Alarmaren tonua"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Alarmaren soinu lehenetsia"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Iraungi egin da tenporizadorea"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Isilik modua"</string>
<string name="ringtone" msgid="9110746249688559579">"Tonua"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Hiriak"</string>
<string name="clock_settings" msgid="8317286807280600391">"Erlojua"</string>
<string name="clock_style" msgid="2265011060429742344">"Estiloa"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Aldatu data eta ordua"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Aldatu data eta ordua"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogikoa"</item>
<item msgid="8483930821046925592">"Digitala"</item>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 2e7d138..333dd35 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"لرزش"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"تکرار"</string>
<string name="alert" msgid="6506982899651975645">"آهنگ زنگ هشدار"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"آهنگ زنگ پیشفرض"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"تایمر به پایان رسید"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"بیصدا"</string>
<string name="ringtone" msgid="9110746249688559579">"آهنگ زنگ"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"شهرها"</string>
<string name="clock_settings" msgid="8317286807280600391">"ساعت"</string>
<string name="clock_style" msgid="2265011060429742344">"سبک"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"تغییر تاریخ و زمان"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"تغییر تاریخ و زمان"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"آنالوگ"</item>
<item msgid="8483930821046925592">"دیجیتال"</item>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index c53290f..f19be1e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Värinä"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Toisto"</string>
<string name="alert" msgid="6506982899651975645">"Herätyksen soittoääni"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Herätyksen oletusääni"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Ajastin lopussa"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Äänetön"</string>
<string name="ringtone" msgid="9110746249688559579">"Soittoääni"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Kaupungit"</string>
<string name="clock_settings" msgid="8317286807280600391">"Kello"</string>
<string name="clock_style" msgid="2265011060429742344">"Tyyli"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Vaihda päivämäärä ja aika"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Vaihda päivämäärä ja aika"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoginen"</item>
<item msgid="8483930821046925592">"Digitaalinen"</item>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index e8a77ec..8cdc8e6 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibreur"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Répéter"</string>
<string name="alert" msgid="6506982899651975645">"Sonnerie de l\'alarme"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Son par défaut pour l\'alarme"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Minuterie expirée"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Mode silencieux"</string>
<string name="ringtone" msgid="9110746249688559579">"Sonnerie"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Villes"</string>
<string name="clock_settings" msgid="8317286807280600391">"Horloge"</string>
<string name="clock_style" msgid="2265011060429742344">"Style"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Modifier la date et l\'heure"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Modifier la date et l\'heure"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogique"</item>
<item msgid="8483930821046925592">"Numérique"</item>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index d8a7fab..64d271f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibreur"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Répéter"</string>
<string name="alert" msgid="6506982899651975645">"Sonnerie de l\'alarme"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Son de l\'alarme par défaut"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Minuteur arrivé à expiration"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencieux"</string>
<string name="ringtone" msgid="9110746249688559579">"Sonnerie"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Villes"</string>
<string name="clock_settings" msgid="8317286807280600391">"Horloge"</string>
<string name="clock_style" msgid="2265011060429742344">"Style"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Modifier la date et l\'heure"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Modifier la date et l\'heure"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogique"</item>
<item msgid="8483930821046925592">"Numérique"</item>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 1b7e11b..56575d1 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetir"</string>
<string name="alert" msgid="6506982899651975645">"Ton de chamada da alarma"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Son de alarma predeterminado"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Finalizou o temporizador"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencio"</string>
<string name="ringtone" msgid="9110746249688559579">"Ton de chamada"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cidades"</string>
<string name="clock_settings" msgid="8317286807280600391">"Reloxo"</string>
<string name="clock_style" msgid="2265011060429742344">"Estilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Cambiar data e hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Cambiar data e hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analóxico"</item>
<item msgid="8483930821046925592">"Dixital"</item>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 09d80f0..f086081 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"વાઇબ્રેટ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"પુનરાવર્તન"</string>
<string name="alert" msgid="6506982899651975645">"એલાર્મ રિંગટોન"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ડિફોલ્ટ એલાર્મ ધ્વનિ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ટાઇમરની સમય સીમા સમાપ્ત થઈ"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"શાંત"</string>
<string name="ringtone" msgid="9110746249688559579">"રિંગટોન"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"શહેરો"</string>
<string name="clock_settings" msgid="8317286807280600391">"ઘડિયાળ"</string>
<string name="clock_style" msgid="2265011060429742344">"શૈલી"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"તારીખ અને સમય બદલો"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"તારીખ અને સમય બદલો"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"એનાલોગ"</item>
<item msgid="8483930821046925592">"ડિજિટલ"</item>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 7a6c306..2eb26ce 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"कंपन"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"दोहराएं"</string>
<string name="alert" msgid="6506982899651975645">"अलार्म रिंगटोन"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"डिफ़ॉल्ट अलार्म ध्वनि"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"टाइमर की समय सीमा समाप्त हो गई"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"मौन"</string>
<string name="ringtone" msgid="9110746249688559579">"रिंगटोन"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"शहर"</string>
<string name="clock_settings" msgid="8317286807280600391">"घड़ी"</string>
<string name="clock_style" msgid="2265011060429742344">"शैली"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"दिनांक और समय बदलना"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"दिनांक और समय बदलें"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ऐनालॉग"</item>
<item msgid="8483930821046925592">"डिजिटल"</item>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 7bd7619..924cff1 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibracija"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ponovi"</string>
<string name="alert" msgid="6506982899651975645">"Melodija alarma"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Zadani zvuk alarma"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Tajmer je istekao"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Bešumno"</string>
<string name="ringtone" msgid="9110746249688559579">"Zvuk zvona"</string>
@@ -244,7 +245,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Gradovi"</string>
<string name="clock_settings" msgid="8317286807280600391">"Sat"</string>
<string name="clock_style" msgid="2265011060429742344">"Stil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Promijeni datum i vrijeme"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Promijeni datum i vrijeme"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogni"</item>
<item msgid="8483930821046925592">"Digitalni"</item>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index fa29b6f..856886b 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Rezgés"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ismétlődés"</string>
<string name="alert" msgid="6506982899651975645">"Ébresztés csengőhangja"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Alapértelmezett ébresztési hang"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Az időzítő lejárt"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Néma"</string>
<string name="ringtone" msgid="9110746249688559579">"Csengőhang"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Városok"</string>
<string name="clock_settings" msgid="8317286807280600391">"Óra"</string>
<string name="clock_style" msgid="2265011060429742344">"Stílus"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Dátum és idő módosítása"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Dátum és idő módosítása"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analóg"</item>
<item msgid="8483930821046925592">"Digitális"</item>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 4764169..4a9e41f 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Թրթռալ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Կրկնել"</string>
<string name="alert" msgid="6506982899651975645">"Զարթուցիչի զանգերանգը"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Զարթուցիչի կանխադրված ձայնը"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Ժամաչափի ժամանակը սպառվել է"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Լուռ"</string>
<string name="ringtone" msgid="9110746249688559579">"Զանգերանգ"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Քաղաքներ"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ժամացույց"</string>
<string name="clock_style" msgid="2265011060429742344">"Տեսակը"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Ամսաթվի և ժամի փոփոխում"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Ամսաթվի և ժամի փոփոխում"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Անալոգ"</item>
<item msgid="8483930821046925592">"Թվային"</item>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 4731c27..bab0202 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Getar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ulangi"</string>
<string name="alert" msgid="6506982899651975645">"Nada Dering Alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Suara alarm default"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Pewaktu Berakhir"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Senyap"</string>
<string name="ringtone" msgid="9110746249688559579">"Nada Dering"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Kota"</string>
<string name="clock_settings" msgid="8317286807280600391">"Jam"</string>
<string name="clock_style" msgid="2265011060429742344">"Gaya"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Ubah Tanggal & waktu"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Ubah tanggal & waktu"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index b927e86..daf0438 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Titringur"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Endurtaka"</string>
<string name="alert" msgid="6506982899651975645">"Hringitónn vekjara"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Sjálfgefið hljóð í vekjara"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Teljari útrunninn"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Hljóðlaus"</string>
<string name="ringtone" msgid="9110746249688559579">"Hringitónn"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Borgir"</string>
<string name="clock_settings" msgid="8317286807280600391">"Klukka"</string>
<string name="clock_style" msgid="2265011060429742344">"Stíll"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Breyta dagsetningu og tíma"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Breyta dag- og tímasetningu"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Með vísum"</item>
<item msgid="8483930821046925592">"Stafræn"</item>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 34fbb28..9c1f88c 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrazione"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ripeti"</string>
<string name="alert" msgid="6506982899651975645">"Suoneria sveglia"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Suono sveglia predefinito"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer scaduto"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silenzioso"</string>
<string name="ringtone" msgid="9110746249688559579">"Suoneria"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Città"</string>
<string name="clock_settings" msgid="8317286807280600391">"Orologio"</string>
<string name="clock_style" msgid="2265011060429742344">"Stile"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Modifica data e ora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Modifica data e ora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogico"</item>
<item msgid="8483930821046925592">"Digitale"</item>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 7b6adae..d6f7a34 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"רטט"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"חוזר"</string>
<string name="alert" msgid="6506982899651975645">"צלצול שעון מעורר"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"צליל ברירת המחדל להתראה"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"הטיימר סיים"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"שקט"</string>
<string name="ringtone" msgid="9110746249688559579">"רינגטון"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ערים"</string>
<string name="clock_settings" msgid="8317286807280600391">"שעון"</string>
<string name="clock_style" msgid="2265011060429742344">"סגנון"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"שנה תאריך ושעה"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"שינוי תאריך ושעה"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"אנלוגי"</item>
<item msgid="8483930821046925592">"דיגיטלי"</item>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index eda6d1d..f151946 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"バイブレーション"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"繰り返し"</string>
<string name="alert" msgid="6506982899651975645">"アラーム音"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"デフォルトの警告音"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"タイマーの完了時"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"マナーモード"</string>
<string name="ringtone" msgid="9110746249688559579">"着信音"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"世界時計"</string>
<string name="clock_settings" msgid="8317286807280600391">"時計"</string>
<string name="clock_style" msgid="2265011060429742344">"スタイル"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"日付と時刻の変更"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"日付と時刻の変更"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"アナログ"</item>
<item msgid="8483930821046925592">"デジタル"</item>
@@ -345,7 +346,7 @@
<string name="description_direction_left" msgid="7448141043674998679">"左にスワイプするとスヌーズを設定できます"</string>
<string name="description_direction_both" msgid="1841309486023845685">"左にスワイプでスヌーズを設定、右にスワイプで解除できます"</string>
<string name="timer_settings" msgid="7955522143086154795">"タイマー"</string>
- <string name="timer_ringtone_title" msgid="7630214935791599619">"タイマーの着信音です"</string>
+ <string name="timer_ringtone_title" msgid="7630214935791599619">"アラーム音"</string>
<string name="timer_stopped" msgid="2730331837832462008">"タイマーが停止しました"</string>
<string name="timer_paused" msgid="5941160896040771462">"タイマーを一時停止しました"</string>
<string name="timers_stopped" msgid="3186191253226005149">"<xliff:g id="NUMBER">%d</xliff:g>個のタイマーを一時停止しました"</string>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 26ea70d..6b765c2 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ვიბრაცია"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"გამეორება"</string>
<string name="alert" msgid="6506982899651975645">"მაღვიძარას ზარი"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"მაღვიძარას ნაგულისხმევი ხმა"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ტაიმერის დრო ამოიწურა"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"უხმო"</string>
<string name="ringtone" msgid="9110746249688559579">"ზარი"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ქალაქები"</string>
<string name="clock_settings" msgid="8317286807280600391">"საათი"</string>
<string name="clock_style" msgid="2265011060429742344">"სტილი"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"დროისა და თარიღის შეცვლა"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"თარიღისა და დროის შეცვლა"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ანალოგი"</item>
<item msgid="8483930821046925592">"ციფრული"</item>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index aca0664..5ccafc7 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Діріл"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Қайталау"</string>
<string name="alert" msgid="6506982899651975645">"Дабылдың қоңырау әуені"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Әдепкі дабыл дыбысы"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Таймер мерзімі бітті"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Үнсіз"</string>
<string name="ringtone" msgid="9110746249688559579">"Қоңырау әуені"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Қалалар"</string>
<string name="clock_settings" msgid="8317286807280600391">"Cағат"</string>
<string name="clock_style" msgid="2265011060429742344">"Стиль"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Күнді және уақытты өзгерту"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Күнді және уақытты өзгерту"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналогтық"</item>
<item msgid="8483930821046925592">"Сандық"</item>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 6e162a2..8ff855e 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ញ័រ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ធ្វើម្ដងទៀត"</string>
<string name="alert" msgid="6506982899651975645">"សំឡេងរោទ៍"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"សំឡេងម៉ោងរោទិ៍លំនាំដើម"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"កម្មវិធីកំណត់ពេលបានផុតកំណត់"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"ស្ងាត់"</string>
<string name="ringtone" msgid="9110746249688559579">"សំឡេងរោទ៍"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ទីក្រុង"</string>
<string name="clock_settings" msgid="8317286807280600391">"នាឡិកា"</string>
<string name="clock_style" msgid="2265011060429742344">"រចនាប័ទ្ម"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ប្តូរកាលបរិច្ឆេទ និងម៉ោង"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ប្តូរកាលបរិច្ឆេទ និងម៉ោង"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"អាណាឡូក"</item>
<item msgid="8483930821046925592">"ឌីជីថល"</item>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 065d484..8b8822f 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ವೈಬ್ರೇಟ್"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ಪುನರಾವರ್ತನೆ"</string>
<string name="alert" msgid="6506982899651975645">"ಅಲಾರಂ ರಿಂಗ್ಟೋನ್"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ಡೀಫಾಲ್ಟ್ ಅಲಾರಮ್ ಧ್ವನಿ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ಟೈಮರ್ ಅವಧಿ ಮೀರಿದೆ"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"ನಿಶ್ಯಬ್ಧ"</string>
<string name="ringtone" msgid="9110746249688559579">"ರಿಂಗ್ಟೋನ್"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ನಗರಗಳು"</string>
<string name="clock_settings" msgid="8317286807280600391">"ಗಡಿಯಾರ"</string>
<string name="clock_style" msgid="2265011060429742344">"ಶೈಲಿ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ದಿನಾಂಕ ಮತ್ತು ಸಮಯವನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ದಿನಾಂಕ & ಸಮಯವನ್ನು ಬದಲಾಯಿಸಿ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ಅನಲಾಗ್"</item>
<item msgid="8483930821046925592">"ಡಿಜಿಟಲ್"</item>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f7dc66f..e2cae30 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"진동"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"반복"</string>
<string name="alert" msgid="6506982899651975645">"알람 벨소리"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"기본 알람 소리"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"타이머 만료됨"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"무음"</string>
<string name="ringtone" msgid="9110746249688559579">"벨소리"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"도시"</string>
<string name="clock_settings" msgid="8317286807280600391">"시계"</string>
<string name="clock_style" msgid="2265011060429742344">"종류"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"날짜 및 시간 변경"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"날짜 및 시간 변경"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"아날로그"</item>
<item msgid="8483930821046925592">"디지털"</item>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 4dd990b..34e2895 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Титирет"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Кайталоо"</string>
<string name="alert" msgid="6506982899651975645">"Ойготкучтун шыңгыры"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Демейки ойготкуч добушу"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Таймердин мөөнөтү бүттү"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Үнсүз"</string>
<string name="ringtone" msgid="9110746249688559579">"Шыңгыр"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Шаарлар"</string>
<string name="clock_settings" msgid="8317286807280600391">"Саат"</string>
<string name="clock_style" msgid="2265011060429742344">"Стиль"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Датаны & убакытты өзгөртүү"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Күндү жана убакытты өзгөртүү"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналог"</item>
<item msgid="8483930821046925592">"Санариптик"</item>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 78ea399..909a99c 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ສັ່ນເຕືອນ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ປຸກຊ້ຳ"</string>
<string name="alert" msgid="6506982899651975645">"ສຽງໂມງປຸກ"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ສຽງໂມງປຸກຕາມຄ່າເລີ່ມຕົ້ນ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ເຄື່ອງຈັບເວລາໝົດອາຍຸແລ້ວ"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"ປິດສຽງ"</string>
<string name="ringtone" msgid="9110746249688559579">"ສຽງໂມງປຸກ"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ເມືອງ"</string>
<string name="clock_settings" msgid="8317286807280600391">"ໂມງ"</string>
<string name="clock_style" msgid="2265011060429742344">"ຮູບແບບ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ປ່ຽນແປງວັນທີ ແລະ ເວລາ"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ປ່ຽນວັນທີ ແລະ ເວລາ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ໂມງເຂັມ"</item>
<item msgid="8483930821046925592">"ດິຈິຕອນ"</item>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 7c6af3a..d4d95fa 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibruoti"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Kartoti"</string>
<string name="alert" msgid="6506982899651975645">"Signalo skambėjimo tonas"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Numatytasis signalo garsas"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Baigėsi laikmačio galiojimas"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Begarsis"</string>
<string name="ringtone" msgid="9110746249688559579">"Skambėjimo tonas"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Miestai"</string>
<string name="clock_settings" msgid="8317286807280600391">"Laikrodis"</string>
<string name="clock_style" msgid="2265011060429742344">"Stilius"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Pakeisti datą ir laiką"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Pakeisti datą ir laiką"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoginis"</item>
<item msgid="8483930821046925592">"Skaitmeninis"</item>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index eb13ed5..7e6eb48 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrozvans"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Atkārtošana"</string>
<string name="alert" msgid="6506982899651975645">"Modinātāja signāls"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Signāla noklusējuma skaņa"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Taimera laiks ir beidzies"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Klusums"</string>
<string name="ringtone" msgid="9110746249688559579">"Zvana signāls"</string>
@@ -244,7 +245,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Pilsētas"</string>
<string name="clock_settings" msgid="8317286807280600391">"Pulkstenis"</string>
<string name="clock_style" msgid="2265011060429742344">"Stils"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Datuma un laika maiņa"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Mainīt datumu un laiku"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogais"</item>
<item msgid="8483930821046925592">"Digitālais"</item>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index f61e9dd..1f3e573 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Вибрации"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Се повторува"</string>
<string name="alert" msgid="6506982899651975645">"Мелодија за аларм"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Стандарден звук за аларм"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Тајмерот истече"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Тивка мелодија"</string>
<string name="ringtone" msgid="9110746249688559579">"Мелодија"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Градови"</string>
<string name="clock_settings" msgid="8317286807280600391">"Часовник"</string>
<string name="clock_style" msgid="2265011060429742344">"Стил"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Промени ги датумот и времето"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Променете ги датумот и времето"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналоген"</item>
<item msgid="8483930821046925592">"Дигитален"</item>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 3bbdd16..5425912 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"വൈബ്രേറ്റുചെയ്യുക"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ആവർത്തിക്കുക"</string>
<string name="alert" msgid="6506982899651975645">"അലാറം റിംഗ്ടോൺ"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ഡിഫോൾട്ട് അലാറം ശബ്ദം"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ടൈമർ കാലഹരണപ്പെട്ടു"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"നിശബ്ദം"</string>
<string name="ringtone" msgid="9110746249688559579">"റിംഗ്ടോൺ"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"നഗരങ്ങൾ"</string>
<string name="clock_settings" msgid="8317286807280600391">"ക്ലോക്ക്"</string>
<string name="clock_style" msgid="2265011060429742344">"സ്റ്റൈൽ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"തീയതിയും സമയവും മാറ്റുക"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"തീയതിയും സമയവും മാറ്റുക"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"അനലോഗ്"</item>
<item msgid="8483930821046925592">"ഡിജിറ്റൽ"</item>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index b92e43f..f0b6f45 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Чичиргээ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Давтах"</string>
<string name="alert" msgid="6506982899651975645">"Сэрүүлгийн ая"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Сэрүүлгийн үндсэн дуу"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Цаг хэмжигчийн хугацаа дууссан"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Чимээгүй"</string>
<string name="ringtone" msgid="9110746249688559579">"Хонхны ая"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Хотууд"</string>
<string name="clock_settings" msgid="8317286807280600391">"Цаг"</string>
<string name="clock_style" msgid="2265011060429742344">"Загвар"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Огноо, цагийг өөрчлөх"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Огноо, цагийг өөрчлөх"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Aналог"</item>
<item msgid="8483930821046925592">"Дижитал"</item>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 851393a..5261d07 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"कंपन"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"पुनरावृत्ती:"</string>
<string name="alert" msgid="6506982899651975645">"अलार्म रिंगटोन"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"डीफॉल्ट अलार्म ध्वनी"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"टायमर कालबाह्य झाला"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"मूक"</string>
<string name="ringtone" msgid="9110746249688559579">"रिंगटोन"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"शहरे"</string>
<string name="clock_settings" msgid="8317286807280600391">"घड्याळ"</string>
<string name="clock_style" msgid="2265011060429742344">"शैली"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"तारीख आणि वेळ बदला"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"तारीख आणि वेळ बदला"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"अॅनालॉग"</item>
<item msgid="8483930821046925592">"डिजिटल"</item>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 217e2d2..560ed27 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Getar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ulang"</string>
<string name="alert" msgid="6506982899651975645">"Nada Dering Penggera"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Bunyi penggera lalai"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Pemasa Tamat"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Senyap"</string>
<string name="ringtone" msgid="9110746249688559579">"Nada dering"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Bandar"</string>
<string name="clock_settings" msgid="8317286807280600391">"Jam"</string>
<string name="clock_style" msgid="2265011060429742344">"Gaya"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Tukar Tarikh & masa"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Tukar tarikh & masa"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 16b6189..90673d5 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"တုန်ခါရန်"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ထပ်လုပ်ရန်"</string>
<string name="alert" msgid="6506982899651975645">"နှိုးစက် သံစဉ်"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ပုံသေ နှိုးစက်အသံ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"အချိန်တိုင်းကိရိယာ သက်တမ်းကုန်ဆုံးပါပြီ"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"အသံတိတ်ရန်"</string>
<string name="ringtone" msgid="9110746249688559579">"သံစဉ်"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"မြို့များ"</string>
<string name="clock_settings" msgid="8317286807280600391">"နာရီ"</string>
<string name="clock_style" msgid="2265011060429742344">"ပုံစံ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ရက်စွဲ & amp; အချိန် ပြောင်းရန်"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ရက်စွဲ & amp; အချိန်ကို ပြောင်းပါ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"လက်တံနာရီ"</item>
<item msgid="8483930821046925592">"ဒီဂျစ်တယ်"</item>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 7cb0aeb..e036146 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrer"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Gjenta"</string>
<string name="alert" msgid="6506982899651975645">"Ringetone for alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Standard alarmlyd"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Tidtakeren er utgått"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Lydløs"</string>
<string name="ringtone" msgid="9110746249688559579">"Ringetone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Byer"</string>
<string name="clock_settings" msgid="8317286807280600391">"Klokke"</string>
<string name="clock_style" msgid="2265011060429742344">"Stil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Endre dato og tid"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Endre dato og tid"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 9b13cf4..29ae509 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"भाइब्रेट गराउनुहोस्"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"दोहोर्याउनुहोस्"</string>
<string name="alert" msgid="6506982899651975645">"अलार्म रिङटोन"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"पूर्वनिर्धारित अलार्म ध्वनि"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"टाइमरको म्याद सकियो"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"मौन"</string>
<string name="ringtone" msgid="9110746249688559579">"रिङटोन"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"शहरहरू"</string>
<string name="clock_settings" msgid="8317286807280600391">"घडी"</string>
<string name="clock_style" msgid="2265011060429742344">"शैली"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"मिति र समय परिवर्तन गर्नुहोस्"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"मिति & समय परिवर्तन गर्नुहोस्"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"एनालग"</item>
<item msgid="8483930821046925592">"डिजिटल"</item>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 7b1b0a0..d1a3805 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Trillen"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Herhalen"</string>
<string name="alert" msgid="6506982899651975645">"Beltoon voor alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Standaardalarmgeluid"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer verlopen"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Stil"</string>
<string name="ringtone" msgid="9110746249688559579">"Beltoon"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Plaatsen"</string>
<string name="clock_settings" msgid="8317286807280600391">"Klok"</string>
<string name="clock_style" msgid="2265011060429742344">"Stijl"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Datum en tijd wijzigen"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Datum en tijd wijzigen"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analoog"</item>
<item msgid="8483930821046925592">"Digitaal"</item>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 2de443f..1582dd0 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"ਵਾਈਬ੍ਰੇਟ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ਦੁਹਰਾਓ"</string>
<string name="alert" msgid="6506982899651975645">"ਅਲਾਰਮ ਰਿੰਗਟੋਨ"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਅਲਾਰਮ ਧੁਨੀ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ਟਾਈਮਰ ਦੀ ਮਿਆਦ ਪੁੱਗੀ"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"ਸਾਈਲੈਂਟ"</string>
<string name="ringtone" msgid="9110746249688559579">"ਰਿੰਗਟੋਨ"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"ਸ਼ਹਿਰ"</string>
<string name="clock_settings" msgid="8317286807280600391">"ਘੜੀ"</string>
<string name="clock_style" msgid="2265011060429742344">"ਸਟਾਈਲ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"ਤਾਰੀਖ & ਸਮਾਂ ਬਦਲੋ"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"ਮਿਤੀ ਅਤੇ ਸਮਾਂ ਬਦਲੋ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ਐਨਾਲਾਗ"</item>
<item msgid="8483930821046925592">"ਡਿਜੀਟਲ"</item>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 945fd1c..d9c9ae8 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Wibracje"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Powtarzanie"</string>
<string name="alert" msgid="6506982899651975645">"Dźwięk alarmu"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Domyślny dźwięk alarmu"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Minutnik wygasł"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Cichy"</string>
<string name="ringtone" msgid="9110746249688559579">"Dzwonek"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Miasta"</string>
<string name="clock_settings" msgid="8317286807280600391">"Zegar"</string>
<string name="clock_style" msgid="2265011060429742344">"Wygląd"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Zmień datę i godzinę"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Zmień datę i godzinę"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogowy"</item>
<item msgid="8483930821046925592">"Cyfrowy"</item>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 1b38ab3..7006287 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetir"</string>
<string name="alert" msgid="6506982899651975645">"Toque do Alarme"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Som de alarme predefinido"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Temporizador expirado"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencioso"</string>
<string name="ringtone" msgid="9110746249688559579">"Toque"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cidades"</string>
<string name="clock_settings" msgid="8317286807280600391">"Relógio"</string>
<string name="clock_style" msgid="2265011060429742344">"Estilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Alterar data e hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Alterar data e hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analógico"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index c29ecbe..c4e8b35 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrar"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetir"</string>
<string name="alert" msgid="6506982899651975645">"Toque do alarme"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Som de alarme padrão"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timer expirado"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silencioso"</string>
<string name="ringtone" msgid="9110746249688559579">"Toque"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Cidades"</string>
<string name="clock_settings" msgid="8317286807280600391">"Relógio"</string>
<string name="clock_style" msgid="2265011060429742344">"Estilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Alterar data e hora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Alterar data e hora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analógico"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index ab45eb0..72c7592 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrare"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Repetă"</string>
<string name="alert" msgid="6506982899651975645">"Ton de apel pentru alarmă"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Sunet de alarmă prestabilit"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Temporizatorul a expirat"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Silențios"</string>
<string name="ringtone" msgid="9110746249688559579">"Ton de apel"</string>
@@ -244,7 +245,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Orașe"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ceas"</string>
<string name="clock_style" msgid="2265011060429742344">"Stil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Schimbați Data și ora"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Schimbați data și ora"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogic"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 34e068d..337602f 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Вибросигнал"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Повторять"</string>
<string name="alert" msgid="6506982899651975645">"Звонок будильника"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Звуковой сигнал по умолчанию"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Время истекло"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Без звука"</string>
<string name="ringtone" msgid="9110746249688559579">"Рингтон"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Города"</string>
<string name="clock_settings" msgid="8317286807280600391">"Часы"</string>
<string name="clock_style" msgid="2265011060429742344">"Стиль"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Изменить дату и время"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Изменение даты и времени"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Стрелки"</item>
<item msgid="8483930821046925592">"Цифры"</item>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index b4df0e2..185eba5 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"කම්පනය වීම"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"නැවත කරන්න"</string>
<string name="alert" msgid="6506982899651975645">"ඇඟවීම් රිංග්ටෝනය"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"පෙරනිමි එලාම හඬ"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ටයිමරය කල් ඉකුත් විය"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"නිහඬ"</string>
<string name="ringtone" msgid="9110746249688559579">"රිංග්ටෝනය"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"නගර"</string>
<string name="clock_settings" msgid="8317286807280600391">"ඔරලෝසුව"</string>
<string name="clock_style" msgid="2265011060429742344">"විලාසය"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"දිනය සහ වේලාව වෙනස් කරන්න"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"දිනය සහ වේලාව වෙනස් කරන්න"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"ප්රතිසමය"</item>
<item msgid="8483930821046925592">"ඩිජිටල්"</item>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index add4f04..8145d5b 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrovať"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Opakovať"</string>
<string name="alert" msgid="6506982899651975645">"Tón zvonenia budíka"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Predvolený zvuk budíka"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Časovač vypršal"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Tichý"</string>
<string name="ringtone" msgid="9110746249688559579">"Tón zvonenia"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Mestá"</string>
<string name="clock_settings" msgid="8317286807280600391">"Hodiny"</string>
<string name="clock_style" msgid="2265011060429742344">"Štýl"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Zmeniť dátum a čas"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Zmeniť dátum a čas"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analógové"</item>
<item msgid="8483930821046925592">"Digitálne"</item>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 9c5f515..64bbf4c 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibriranje"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ponovi"</string>
<string name="alert" msgid="6506982899651975645">"Ton zvonjenja za alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Privzeti zvok alarma"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Časovnik je potekel"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Tiho"</string>
<string name="ringtone" msgid="9110746249688559579">"Melodija zvonjenja"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Mesta"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ura"</string>
<string name="clock_style" msgid="2265011060429742344">"Slog"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Spreminjanje datuma in ure"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Spreminjanje datuma in ure"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogno"</item>
<item msgid="8483930821046925592">"Digitalno"</item>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 3ca6a48..2a4e673 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Dridhja"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Përsërit"</string>
<string name="alert" msgid="6506982899651975645">"Zilja e alarmit"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Tingulli i parazgjedhur i alarmit sinjalizues"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Kohëmatësi skadoi"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Në heshtje"</string>
<string name="ringtone" msgid="9110746249688559579">"Zilja"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Qytetet"</string>
<string name="clock_settings" msgid="8317286807280600391">"Ora"</string>
<string name="clock_style" msgid="2265011060429742344">"Stili"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Ndërro datën dhe kohën"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Ndërro datën dhe orën"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Dixhital"</item>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index b88158f..e1aa20c 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Вибрација"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Понови"</string>
<string name="alert" msgid="6506982899651975645">"Мелодија аларма"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Подразумевани звук аларма"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Тајмер је истекао"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Нечујно"</string>
<string name="ringtone" msgid="9110746249688559579">"Мелодија звона"</string>
@@ -244,7 +245,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Градови"</string>
<string name="clock_settings" msgid="8317286807280600391">"Сат"</string>
<string name="clock_style" msgid="2265011060429742344">"Стил"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Промените датум и време"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Промени датум и време"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналогни"</item>
<item msgid="8483930821046925592">"Дигитални"</item>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 66bb405..99bea70 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Vibrera"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Upprepa"</string>
<string name="alert" msgid="6506982899651975645">"Ringsignal för alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Standardljud för alarm"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Timern har upphört"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Tyst"</string>
<string name="ringtone" msgid="9110746249688559579">"Ringsignal"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Orter"</string>
<string name="clock_settings" msgid="8317286807280600391">"Klocka"</string>
<string name="clock_style" msgid="2265011060429742344">"Format"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Ändra datum och tid"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Ändra datum och tid"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index e53b828..b6475a0 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Mtetemo"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Rudia"</string>
<string name="alert" msgid="6506982899651975645">"Mlio wa Kengele"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Sauti chaguo-msingi ya kengele"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Muda wa Kipima wakati Umemalizika"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Kimya"</string>
<string name="ringtone" msgid="9110746249688559579">"Mlio wa simu"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Miji"</string>
<string name="clock_settings" msgid="8317286807280600391">"Saa"</string>
<string name="clock_style" msgid="2265011060429742344">"Mtindo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Badilisha Tarehe na wakati"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Badilisha tarehe na saa"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analogi"</item>
<item msgid="8483930821046925592">"Dijito"</item>
diff --git a/res/values-sw600dp-land/config.xml b/res/values-sw600dp-land/config.xml
deleted file mode 100644
index 5a1fd2b..0000000
--- a/res/values-sw600dp-land/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <item type="integer" name="timer_column_count">2</item>
-</resources>
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index d9741ce..9fbceac 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -3,22 +3,22 @@
/*
** Copyright 2011, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+<resources>
<bool name="config_rotateAlarmAlert">true</bool>
</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index c48565e..11d3ef7 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"அதிர்வு"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"மீண்டும்"</string>
<string name="alert" msgid="6506982899651975645">"அலார ரிங்டோன்"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"இயல்பு அலார ஒலி"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"டைமர் காலாவதியானது"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"நிசப்தம்"</string>
<string name="ringtone" msgid="9110746249688559579">"ரிங்டோன்"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"நகரங்கள்"</string>
<string name="clock_settings" msgid="8317286807280600391">"கடிகாரம்"</string>
<string name="clock_style" msgid="2265011060429742344">"வகை"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"தேதி & நேரத்தை மாற்று"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"தேதி & நேரத்தை மாற்று"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"அனலாக்"</item>
<item msgid="8483930821046925592">"டிஜிட்டல்"</item>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 4599da0..034c878 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"వైబ్రేట్"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"పునరావృతం చేయి"</string>
<string name="alert" msgid="6506982899651975645">"అలారం రింగ్టోన్"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"డిఫాల్ట్ అలారం ధ్వని"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"టైమర్ గడువు ముగిసింది"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"నిశ్శబ్దం"</string>
<string name="ringtone" msgid="9110746249688559579">"రింగ్టోన్"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"నగరాలు"</string>
<string name="clock_settings" msgid="8317286807280600391">"గడియారం"</string>
<string name="clock_style" msgid="2265011060429742344">"శైలి"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"తేదీ & సమయం మార్చండి"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"తేదీ & సమయాన్ని మార్చండి"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"అనలాగ్"</item>
<item msgid="8483930821046925592">"డిజిటల్"</item>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c360f0f..3256631 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"สั่น"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"ตั้งซ้ำ"</string>
<string name="alert" msgid="6506982899651975645">"เสียงเตือน"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"เสียงปลุกเริ่มต้น"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"การจับเวลาสิ้นสุด"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"เงียบ"</string>
<string name="ringtone" msgid="9110746249688559579">"เสียงเรียกเข้า"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"เมือง"</string>
<string name="clock_settings" msgid="8317286807280600391">"นาฬิกา"</string>
<string name="clock_style" msgid="2265011060429742344">"รูปแบบ"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"เปลี่ยนแปลงวันที่และเวลา"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"เปลี่ยนแปลงวันที่และเวลา"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"แอนะล็อก"</item>
<item msgid="8483930821046925592">"ดิจิทัล"</item>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index cd19f03..b284e60 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"I-vibrate"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Ulitin"</string>
<string name="alert" msgid="6506982899651975645">"Ringtone ng Alarm"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Default na tunog ng alarm"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Nag-expire na ang Timer"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Naka-silent"</string>
<string name="ringtone" msgid="9110746249688559579">"Ringtone"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Mga Lungsod"</string>
<string name="clock_settings" msgid="8317286807280600391">"Orasan"</string>
<string name="clock_style" msgid="2265011060429742344">"Istilo"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Baguhin ang Petsa & oras"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Baguhin ang petsa at oras"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Digital"</item>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index a1312b7..b39495c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Titreşim"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Tekrarla"</string>
<string name="alert" msgid="6506982899651975645">"Alarm Zil Sesi"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Varsayılan alarm sesi"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Zamanlayıcının Süresi Doldu"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Sessiz"</string>
<string name="ringtone" msgid="9110746249688559579">"Zil sesi"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Şehirler"</string>
<string name="clock_settings" msgid="8317286807280600391">"Saat"</string>
<string name="clock_style" msgid="2265011060429742344">"Stil"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Tarih ve saati değiştir"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Tarih ve saati değiştirin"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Analog"</item>
<item msgid="8483930821046925592">"Dijital"</item>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 7476d52..5586980 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Вібросигнал"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Повторити"</string>
<string name="alert" msgid="6506982899651975645">"Звук сигналу"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Сигнал будильника за умовчанням"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Час таймера вичерпано"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Без звуку"</string>
<string name="ringtone" msgid="9110746249688559579">"Сигнал дзвінка"</string>
@@ -255,7 +256,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Міста"</string>
<string name="clock_settings" msgid="8317286807280600391">"Годинник"</string>
<string name="clock_style" msgid="2265011060429742344">"Стиль"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Змінити дату й час"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Змінити дату й час"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Аналоговий"</item>
<item msgid="8483930821046925592">"Цифровий"</item>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index eb43d0c..19bf977 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"وائبریٹ"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"دہرائیں"</string>
<string name="alert" msgid="6506982899651975645">"الارم رنگ ٹون"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"الارم کی ڈیفالٹ آواز"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"ٹائمر کی معیاد ختم ہو گئی"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"خاموش"</string>
<string name="ringtone" msgid="9110746249688559579">"رنگ ٹون"</string>
@@ -234,7 +235,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"شہر"</string>
<string name="clock_settings" msgid="8317286807280600391">"گھڑی"</string>
<string name="clock_style" msgid="2265011060429742344">"طرز"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"تاریخ اور وقت تبدیل کریں"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"تاریخ اور وقت تبدیل کریں"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"اینالاگ"</item>
<item msgid="8483930821046925592">"ڈیجیٹل"</item>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index 88d7415..2ac930f 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Tebranish"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Takrorlash"</string>
<string name="alert" msgid="6506982899651975645">"Uyg‘otkich ringtoni"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Birlamchi uyg‘otkich ovozi"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Taymer vaqti tugadi"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Ovozsiz"</string>
<string name="ringtone" msgid="9110746249688559579">"Rington"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Shaharlar"</string>
<string name="clock_settings" msgid="8317286807280600391">"Soat"</string>
<string name="clock_style" msgid="2265011060429742344">"Soat turi"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Sana va vaqtni o‘zgartirish"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Sana va vaqtni o‘zgartirish"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Soat mili"</item>
<item msgid="8483930821046925592">"Raqamli"</item>
diff --git a/res/values-v17/config.xml b/res/values-v17/config.xml
deleted file mode 100644
index 79eaf8a..0000000
--- a/res/values-v17/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no need for the dock app, we have Dreams now -->
- <bool name="config_dockAppEnabled">false</bool>
-</resources>
diff --git a/res/values-v21/styles.xml b/res/values-v21/styles.xml
index f9f0763..75cbe5f 100644
--- a/res/values-v21/styles.xml
+++ b/res/values-v21/styles.xml
@@ -14,23 +14,7 @@
limitations under the License.
-->
-<resources>
-
- <style name="SettingsTheme" parent="TranslucentDecorActivityTheme">
- <item name="android:alertDialogTheme">@style/SettingsAlertDialogTheme</item>
- <item name="android:detailsElementBackground">@null</item>
-
- <!-- Attributes from support.v7.appcompat -->
- <item name="actionBarStyle">@style/SettingsActionBarStyle</item>
- <item name="colorControlActivated">?attr/colorAccent</item>
- <item name="windowActionBar">true</item>
- <item name="windowNoTitle">false</item>
- </style>
-
- <!-- Theme that will be used by PreferenceFragment (i.e. *not* AppCompat). -->
- <style name="SettingsAlertDialogTheme" parent="android:Theme.Material.Dialog.Alert">
- <item name="android:colorAccent">?attr/colorAccent</item>
- </style>
+<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Custom notification content styles -->
<!-- copied TextAppearance.Material.Button -->
@@ -41,38 +25,37 @@
<item name="android:textColor">@color/black_54p</item>
</style>
- <style name="TextAppearance.StatusBar.EventContent">
+ <style name="TextAppearance.StatusBar.EventContent" tools:ignore="PrivateResource">
<item name="android:textSize">14sp</item>
<item name="android:textColor">@color/black_54p</item>
</style>
- <style name="TextAppearance.StatusBar.EventContent.Title">
+ <style name="TextAppearance.StatusBar.EventContent.Title" tools:ignore="PrivateResource">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/black_87p</item>
</style>
<style name="TimePickerTheme" parent="Theme.AppCompat.Dialog">
- <item name="android:background">@color/time_picker_gray</item>
+ <item name="android:textColorPrimary">?attr/colorAccent</item>
+ <item name="android:textColorPrimaryInverse">?android:attr/textColorPrimary</item>
+ <item name="android:textColorSecondaryInverse">@color/white</item>
<item name="android:timePickerStyle">@style/TimePickerStyle</item>
- <item name="android:textColorPrimaryInverse">?attr/colorAccent</item>
+ <item name="android:windowBackground">@color/time_picker_gray</item>
<!-- Attributes from support.v7.appcompat -->
<item name="colorAccent">@color/color_accent</item>
</style>
- <style name="TimePickerStyle" parent="@android:style/Widget.Material.TimePicker" >
- <item name="android:headerBackground">@color/time_picker_gray</item>
- <item name="android:headerTimeTextAppearance">@style/TimeLabelTextAppearance</item>
- <item name="android:headerAmPmTextAppearance">@style/AmPmTextAppearance</item>
- <item name="android:numbersBackgroundColor">@color/time_picker_gray</item>
+ <style name="TimePickerStyle" parent="android:Widget.Material.TimePicker" >
+ <item name="android:headerBackground">@android:color/transparent</item>
+ <item name="android:numbersBackgroundColor">@android:color/transparent</item>
<item name="android:numbersTextColor">@color/white</item>
- <item name="android:amPmTextColor">@color/white</item>
</style>
- <style name="PrimaryLabelTextAppearance" parent="@style/PrimaryLabelTextParentAppearance">
+ <style name="PrimaryLabelTextAppearance" parent="PrimaryLabelTextParentAppearance">
<item name="android:fontFamily">sans-serif-medium</item>
</style>
- <style name="SecondaryLabelTextAppearance" parent="@style/SecondaryLabelTextParentAppearance">
+ <style name="SecondaryLabelTextAppearance" parent="SecondaryLabelTextParentAppearance">
<item name="android:fontFamily">sans-serif-medium</item>
</style>
diff --git a/res/values-v23/styles.xml b/res/values-v23/styles.xml
index f394ee1..98c880c 100644
--- a/res/values-v23/styles.xml
+++ b/res/values-v23/styles.xml
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="TimeLabelTextAppearance" parent="TextAppearance.AppCompat">
- <item name="android:textColor">@color/timepicker_time</item>
- <item name="android:textSize">60dp</item>
- </style>
-
- <style name="AmPmTextAppearance" parent="TextAppearance.AppCompat">
- <item name="android:textColor">@color/timepicker_ampm</item>
- <item name="android:textSize">16sp</item>
- </style>
<style name="widget_big_thin" parent="big_thin">
<item name="android:textSize">@dimen/widget_big_font_size</item>
@@ -26,4 +17,5 @@
<item name="android:shadowColor">@color/digital_widget_shadow_color</item>
<item name="android:shadowDy">@dimen/digital_widget_shadow_dy</item>
</style>
-</resources>
\ No newline at end of file
+
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 1ca7a0a..db42258 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Rung"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Lặp lại"</string>
<string name="alert" msgid="6506982899651975645">"Nhạc chuông báo thức"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Âm thanh báo thức mặc định"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Bộ hẹn giờ đã hết hạn"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Im lặng"</string>
<string name="ringtone" msgid="9110746249688559579">"Nhạc chuông"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Thành phố"</string>
<string name="clock_settings" msgid="8317286807280600391">"Đồng hồ"</string>
<string name="clock_style" msgid="2265011060429742344">"Kiểu"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Thay đổi ngày và giờ"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Thay đổi ngày và giờ"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"Đồng hồ kim"</item>
<item msgid="8483930821046925592">"Đồng hồ số"</item>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index f00f207..0c97ec3 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"振动"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"重复"</string>
<string name="alert" msgid="6506982899651975645">"闹钟铃声"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"默认闹钟提示音"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"计时器已结束"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"静音"</string>
<string name="ringtone" msgid="9110746249688559579">"铃声"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"城市"</string>
<string name="clock_settings" msgid="8317286807280600391">"时钟"</string>
<string name="clock_style" msgid="2265011060429742344">"样式"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"更改日期和时间"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"更改日期和时间"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"指针"</item>
<item msgid="8483930821046925592">"数字"</item>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index f5f77ed..fce52bf 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"震動"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"重複"</string>
<string name="alert" msgid="6506982899651975645">"鬧鐘鈴聲"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"預設鬧鐘音效"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"計時器已逾時"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"靜音"</string>
<string name="ringtone" msgid="9110746249688559579">"鈴聲"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"城市"</string>
<string name="clock_settings" msgid="8317286807280600391">"時鐘"</string>
<string name="clock_style" msgid="2265011060429742344">"樣式"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"更改日期和時間"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"變更日期和時間"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"類比"</item>
<item msgid="8483930821046925592">"數碼"</item>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f8f0832..096b377 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"震動"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"重複"</string>
<string name="alert" msgid="6506982899651975645">"鬧鐘鈴聲"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"預設鬧鐘音效"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"計時完畢"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"靜音"</string>
<string name="ringtone" msgid="9110746249688559579">"鈴聲"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"城市"</string>
<string name="clock_settings" msgid="8317286807280600391">"時鐘"</string>
<string name="clock_style" msgid="2265011060429742344">"樣式"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"變更日期和時間"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"變更日期和時間"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"類比"</item>
<item msgid="8483930821046925592">"數位"</item>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index e88bf40..8e5bdc4 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -35,6 +35,7 @@
<string name="alarm_vibrate" msgid="3476686921490362230">"Dlidliza"</string>
<string name="alarm_repeat" msgid="7242985466344233206">"Phindaphinda"</string>
<string name="alert" msgid="6506982899651975645">"Ithoni yokukhala ye-alamu"</string>
+ <string name="default_alarm_ringtone_title" msgid="2916376768509623643">"Umsindo we-alamu ozenzakalelayo"</string>
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"Isibali sikhathi siphelelwe yisikhathi"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"Thulile"</string>
<string name="ringtone" msgid="9110746249688559579">"Ithoni yokukhala"</string>
@@ -233,7 +234,7 @@
<string name="cities_activity_title" msgid="8552462751129256730">"Amadolobha"</string>
<string name="clock_settings" msgid="8317286807280600391">"Iwashi"</string>
<string name="clock_style" msgid="2265011060429742344">"Isitayela"</string>
- <string name="open_date_settings" msgid="5915966847691221307">"Guqula idethi nesikhathi"</string>
+ <string name="open_date_settings" msgid="7712226973337806152">"Shintsha idethi nesikhathi"</string>
<string-array name="clock_style_entries">
<item msgid="917900462224167608">"I-Analog"</item>
<item msgid="8483930821046925592">"Idijithali"</item>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 1e0151c..59f6133 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -16,12 +16,6 @@
-->
<resources>
- <declare-styleable name="AnalogClock">
- <attr name="jewelRadius" format="dimension"/>
- <attr name="jewelOffset" format="dimension"/>
- <attr name="jewelColor" format="color"/>
- </declare-styleable>
-
<declare-styleable name="TextTime">
<!-- Specifies the formatting pattern used to show the time and/or date
in 12-hour mode. Please refer to {@link android.text.format.DateFormat}
diff --git a/res/values/config.xml b/res/values/config.xml
index 855923d..6c879c7 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -17,12 +17,7 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <bool name="config_requiresScreenSaver">true</bool>
- <bool name="config_dockAppEnabled">true</bool>
<bool name="config_rotateAlarmAlert">false</bool>
- <item type="integer" name="timer_column_count">1</item>
<!-- Number of world clocks in a row, for the clock tab. -->
<item type="integer" name="world_clocks_per_row">1</item>
- <!-- Number of world clocks in a row, for the digital appwidget. -->
- <item type="integer" name="appwidget_world_clocks_per_row">2</item>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4184cbc..f68c7df 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -73,7 +73,6 @@
<dimen name="label_font_size">16sp</dimen>
<!-- Use dp on purpose to ensure consistency across multiple screen sizes. -->
<dimen name="widget_label_font_size">14dp</dimen>
- <item name="ampm_font_size_scale" type="fraction">50%</item>
<item name="reduced_clock_font_size_scale" type="fraction">65%</item>
<dimen name="header_font_size">24sp</dimen>
<dimen name="body_font_size">18sp</dimen>
@@ -91,6 +90,7 @@
<dimen name="dialog_button_font_size">16sp</dimen>
<dimen name="alarm_label_size">14sp</dimen>
+ <dimen name="alarm_icon_padding">6dp</dimen>
<dimen name="medium_font_padding">12dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5f18d1d..026b4dd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -76,6 +76,9 @@
<!-- Setting labels on Set alarm screen: Select alarm ringtone -->
<string name="alert">Alarm Ringtone</string>
+ <!-- Title of default ringtone played when an alarm triggers. -->
+ <string name="default_alarm_ringtone_title">Default alarm sound</string>
+
<!-- Title of default ringtone played when a timer expires. -->
<string name="default_timer_ringtone_title">Timer Expired</string>
@@ -347,6 +350,12 @@
<!-- Title for ringtones that cannot be located by uri. -->
<string name="unknown_ringtone_title">Unknown</string>
+ <!-- Text to display when alarm volume is muted. -->
+ <string name="alarm_volume_muted">Alarm volume muted</string>
+
+ <!-- Text to display when silent ringtone is selected. -->
+ <string name="silent_ringtone">Silent ringtone</string>
+
<!-- Text to display in the small text of the notification -->
<string name="alarm_notify_text">Snooze or dismiss alarm.</string>
@@ -571,7 +580,7 @@
<string name="clock_style">Style</string>
<!-- Title for preference to change date & time -->
- <string name="open_date_settings">Change Date \u0026 time</string>
+ <string name="open_date_settings">Change date \u0026 time</string>
<!-- Entries listed in the ListPreference when invoking the clock style
preference. -->
@@ -824,6 +833,8 @@
<string name="timer_settings">Timers</string>
<!-- Description for timer ringtone setting. -->
<string name="timer_ringtone_title">Timer ringtone</string>
+ <!-- Description for timer vibration. -->
+ <string name="timer_vibrate_title">Timer vibrate</string>
<!-- Description when timer is stopped. -->
<string name="timer_stopped">Timer stopped</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ce89f11..fe9fcb3 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -23,10 +23,10 @@
</style>
<style name="BaseActivityTheme" parent="Theme.AppCompat">
- <item name="android:imageButtonStyle">@style/ImageButtonStyle</item>
<item name="android:windowBackground">@color/default_background</item>
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
+ <item name="imageButtonStyle">@style/ImageButtonStyle</item>
<item name="colorAccent">@color/color_accent</item>
<item name="colorPrimaryDark">@color/status_bar</item>
<item name="colorControlActivated">@color/white</item>
@@ -53,16 +53,6 @@
<item name="colorControlActivated">?attr/colorAccent</item>
</style>
- <style name="TimeLabelTextAppearance" parent="TextAppearance.AppCompat">
- <item name="android:textColor">@color/white</item>
- <item name="android:textSize" tools:ignore="SpUsage">60dp</item>
- </style>
-
- <style name="AmPmTextAppearance" parent="TextAppearance.AppCompat">
- <item name="android:textColor">@color/white</item>
- <item name="android:textSize">16sp</item>
- </style>
-
<style name="DeskClockTabBaseStyle" parent="Widget.AppCompat.ActionBar.TabView">
<item name="android:paddingLeft">@dimen/actionbar_tab_padding</item>
<item name="android:paddingRight">@dimen/actionbar_tab_padding</item>
@@ -73,10 +63,18 @@
<item name="android:detailsElementBackground">@null</item>
<!-- Attributes from support.v7.appcompat -->
<item name="actionBarStyle">@style/SettingsActionBarStyle</item>
+ <item name="alertDialogTheme">@style/SettingsAlertDialogTheme</item>
+ <item name="colorControlActivated">?attr/colorAccent</item>
+ <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
<item name="windowActionBar">true</item>
<item name="windowNoTitle">false</item>
</style>
+ <!-- Theme that will be used by PreferenceFragment. -->
+ <style name="SettingsAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
+ <item name="colorAccent">@color/color_accent</item>
+ </style>
+
<style name="SettingsActionBarStyle" parent="@style/Widget.AppCompat.Toolbar">
<item name="android:background">@null</item>
@@ -111,7 +109,7 @@
<style name="ScreensaverActivityTheme" parent="Theme.AppCompat.NoActionBar" />
- <style name="ImageButtonStyle" parent="android:Widget.DeviceDefault.ImageButton">
+ <style name="ImageButtonStyle" parent="Widget.AppCompat.ImageButton">
<item name="android:background">?attr/selectableItemBackgroundBorderless</item>
</style>
@@ -276,12 +274,12 @@
</style>
<!-- Notification content styles -->
- <style name="TextAppearance.StatusBar.EventContent">
+ <style name="TextAppearance.StatusBar.EventContent" tools:ignore="PrivateResource">
<item name="android:textSize">@dimen/notification_text_size</item>
<item name="android:textColor">@color/notif_text_grey</item>
</style>
- <style name="TextAppearance.StatusBar.EventContent.Title">
+ <style name="TextAppearance.StatusBar.EventContent.Title" tools:ignore="PrivateResource">
<item name="android:textSize">@dimen/notification_title_text_size</item>
<item name="android:textColor">@color/white</item>
</style>
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
index 37b416a..4c68956 100644
--- a/res/xml/settings.xml
+++ b/res/xml/settings.xml
@@ -53,19 +53,18 @@
android:defaultValue="10"
android:dialogTitle="@string/auto_silence_title" />
- <com.android.deskclock.settings.SnoozeLengthDialog
+ <com.android.deskclock.settings.SnoozeLengthDialogPreference
android:key="snooze_duration"
- android:title="@string/snooze_duration_title"
- android:defaultValue="10"/>
+ android:title="@string/snooze_duration_title" />
- <Preference
+ <com.android.deskclock.settings.AlarmVolumePreference
android:key="volume_setting"
- android:title="@string/alarm_volume_title" />
+ android:title="@string/alarm_volume_title"
+ android:layout="@layout/alarm_volume_preference"/>
- <com.android.deskclock.settings.CrescendoLengthDialog
+ <com.android.deskclock.settings.CrescendoLengthDialogPreference
android:key="alarm_crescendo_duration"
- android:title="@string/crescendo_duration_title"
- android:defaultValue="0"/>
+ android:title="@string/crescendo_duration_title" />
<ListPreference
android:key="volume_button_setting"
@@ -85,15 +84,18 @@
<PreferenceCategory
android:title="@string/timer_settings">
- <com.android.deskclock.settings.TimerRingtonePreference
+ <Preference
android:key="timer_ringtone"
- android:title="@string/timer_ringtone_title"
- android:ringtoneType="alarm" />
+ android:title="@string/timer_ringtone_title" />
- <com.android.deskclock.settings.CrescendoLengthDialog
+ <com.android.deskclock.settings.CrescendoLengthDialogPreference
android:key="timer_crescendo_duration"
- android:title="@string/crescendo_duration_title"
- android:defaultValue="0"/>
+ android:title="@string/crescendo_duration_title" />
+
+ <SwitchPreference
+ android:key="timer_vibrate"
+ android:title="@string/timer_vibrate_title"
+ android:defaultValue="false" />
</PreferenceCategory>
</PreferenceScreen>
diff --git a/src/com/android/alarmclock/DigitalAppWidgetProvider.java b/src/com/android/alarmclock/DigitalAppWidgetProvider.java
index 5b22544..6b17e4d 100644
--- a/src/com/android/alarmclock/DigitalAppWidgetProvider.java
+++ b/src/com/android/alarmclock/DigitalAppWidgetProvider.java
@@ -24,144 +24,145 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
-import android.util.TypedValue;
import android.view.View;
import android.widget.RemoteViews;
import com.android.deskclock.HandleDeskClockApiCalls;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
-import com.android.deskclock.alarms.AlarmStateManager;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.worldclock.CitySelectionActivity;
import java.util.Locale;
+import static android.app.AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED;
+import static android.app.AlarmManager.RTC;
+import static android.app.PendingIntent.FLAG_NO_CREATE;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+import static android.content.Intent.ACTION_DATE_CHANGED;
+import static android.content.Intent.ACTION_LOCALE_CHANGED;
+import static android.content.Intent.ACTION_SCREEN_ON;
+import static android.content.Intent.ACTION_TIMEZONE_CHANGED;
+import static android.content.Intent.ACTION_TIME_CHANGED;
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
+import static com.android.deskclock.alarms.AlarmStateManager.SYSTEM_ALARM_CHANGE_ACTION;
+import static com.android.deskclock.data.DataModel.ACTION_DIGITAL_WIDGET_CHANGED;
+
public class DigitalAppWidgetProvider extends AppWidgetProvider {
+
private static final String TAG = "DigAppWidgetProvider";
- /**
- * Intent to be used for checking if a world clock's date has changed. Must be every fifteen
- * minutes because not all time zones are hour-locked.
- **/
- public static final String ACTION_ON_QUARTER_HOUR = "com.android.deskclock.ON_QUARTER_HOUR";
+ /** Intent action used for refreshing a world clock's date. See Nepal timezone: UTC+05:45. */
+ private static final String ACTION_ON_QUARTER_HOUR = "com.android.deskclock.ON_QUARTER_HOUR";
- // Lazily creating this intent to use with the AlarmManager
- private PendingIntent mPendingIntent;
+ /** Intent used to deliver the {@link #ACTION_ON_QUARTER_HOUR} callback. */
+ private static final Intent QUARTER_HOUR_INTENT = new Intent(ACTION_ON_QUARTER_HOUR);
+
// Lazily creating this name to use with the AppWidgetManager
private ComponentName mComponentName;
- public DigitalAppWidgetProvider() {
- }
-
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
- startAlarmOnQuarterHour(context);
+
+ // Schedule the quarter-hour callback if necessary.
+ updateQuarterHourCallback(context);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
- cancelAlarmOnQuarterHour(context);
+
+ // Remove any scheduled quarter-hour callback.
+ removeQuarterHourCallback(context);
}
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
if (DigitalAppWidgetService.LOGGING) {
Log.i(TAG, "onReceive: " + action);
}
super.onReceive(context, intent);
- if (ACTION_ON_QUARTER_HOUR.equals(action)
- || Intent.ACTION_DATE_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
- || Intent.ACTION_TIME_CHANGED.equals(action)
- || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- if (appWidgetManager != null) {
- int[] appWidgetIds = appWidgetManager.getAppWidgetIds(getComponentName(context));
+ final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+ if (widgetManager == null) {
+ return;
+ }
+ final int[] appWidgetIds = widgetManager.getAppWidgetIds(getComponentName(context));
+
+ switch (action) {
+ case ACTION_DATE_CHANGED:
+ case ACTION_TIME_CHANGED:
+ case ACTION_LOCALE_CHANGED:
+ case ACTION_ON_QUARTER_HOUR:
+ case ACTION_TIMEZONE_CHANGED:
+ // Time has changed so reschedule the next quarter-hour callback.
+ updateQuarterHourCallback(context);
+
+ final String pName = context.getPackageName();
for (int appWidgetId : appWidgetIds) {
- appWidgetManager.
- notifyAppWidgetViewDataChanged(appWidgetId,
- R.id.digital_appwidget_listview);
- RemoteViews widget = new RemoteViews(context.getPackageName(),
- R.layout.digital_appwidget);
- float ratio = WidgetUtils.getScaleRatio(context, null, appWidgetId);
- WidgetUtils.setTimeFormat(context, widget, false /* showAmPm */,
- R.id.the_clock);
- WidgetUtils.setClockSize(context, widget, ratio);
+ widgetManager.notifyAppWidgetViewDataChanged(appWidgetId,
+ R.id.digital_appwidget_listview);
+ final RemoteViews widget = new RemoteViews(pName, R.layout.digital_appwidget);
+ final float ratio = WidgetUtils.getScaleRatio(context, null, appWidgetId);
refreshAlarm(context, widget, ratio);
- appWidgetManager.partiallyUpdateAppWidget(appWidgetId, widget);
+ WidgetUtils.setClockSize(context, widget, ratio);
+ WidgetUtils.setTimeFormat(context, widget, 0.4f /* amPmRatio */, R.id.clock);
+ widgetManager.partiallyUpdateAppWidget(appWidgetId, widget);
}
- }
- if(!ACTION_ON_QUARTER_HOUR.equals(action)) {
- cancelAlarmOnQuarterHour(context);
- }
- startAlarmOnQuarterHour(context);
- } else if (isNextAlarmChangedAction(action)
- || Intent.ACTION_SCREEN_ON.equals(action)
- || DataModel.ACTION_DIGITAL_WIDGET_CHANGED.equals(action)) {
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- if (appWidgetManager != null) {
- int[] appWidgetIds = appWidgetManager.getAppWidgetIds(getComponentName(context));
+
+ break;
+
+ case ACTION_DIGITAL_WIDGET_CHANGED:
+ // Selected cities have changed so schedule/remove the next quarter-hour callback.
+ updateQuarterHourCallback(context);
+ case ACTION_SCREEN_ON:
+ case SYSTEM_ALARM_CHANGE_ACTION:
+ case ACTION_NEXT_ALARM_CLOCK_CHANGED:
for (int appWidgetId : appWidgetIds) {
final float ratio = WidgetUtils.getScaleRatio(context, null, appWidgetId);
- updateClock(context, appWidgetManager, appWidgetId, ratio);
+ updateClock(context, widgetManager, appWidgetId, ratio);
}
- }
+ break;
}
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
- if (DigitalAppWidgetService.LOGGING) {
- Log.i(TAG, "onUpdate");
- }
+ super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int appWidgetId : appWidgetIds) {
- float ratio = WidgetUtils.getScaleRatio(context, null, appWidgetId);
+ final float ratio = WidgetUtils.getScaleRatio(context, null, appWidgetId);
updateClock(context, appWidgetManager, appWidgetId, ratio);
}
- startAlarmOnQuarterHour(context);
- super.onUpdate(context, appWidgetManager, appWidgetIds);
+
+ updateQuarterHourCallback(context);
}
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, Bundle newOptions) {
+ super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
+
// scale the fonts of the clock to fit inside the new size
- float ratio = WidgetUtils.getScaleRatio(context, newOptions, appWidgetId);
- AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+ final float ratio = WidgetUtils.getScaleRatio(context, newOptions, appWidgetId);
+ final AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
updateClock(context, widgetManager, appWidgetId, ratio);
}
- /**
- * Determine whether action received corresponds to a "next alarm" changed action depending
- * on the SDK version.
- */
- private boolean isNextAlarmChangedAction(String action) {
- final String nextAlarmIntentAction;
- if (Utils.isLOrLater()) {
- nextAlarmIntentAction = AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED;
- } else {
- nextAlarmIntentAction = AlarmStateManager.SYSTEM_ALARM_CHANGE_ACTION;
- }
- return nextAlarmIntentAction.equals(action);
- }
-
- private void updateClock(
- Context context, AppWidgetManager appWidgetManager, int appWidgetId, float ratio) {
+ private void updateClock(Context context, AppWidgetManager widgetManager, int appWidgetId,
+ float ratio) {
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.digital_appwidget);
// Launch clock when clicking on the time in the widget only if not a lock screen widget
- Bundle newOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
+ final Bundle newOptions = widgetManager.getAppWidgetOptions(appWidgetId);
if (newOptions != null &&
newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1)
!= AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
@@ -171,11 +172,11 @@
widget.setOnClickPendingIntent(R.id.digital_appwidget, pendingIntent);
}
- // Setup formats and font sizes
+ // Setup formats and font sizes.
refreshDate(context, widget, ratio);
refreshAlarm(context, widget, ratio);
- WidgetUtils.setTimeFormat(context, widget, false /* showAmPm */, R.id.the_clock);
WidgetUtils.setClockSize(context, widget, ratio);
+ WidgetUtils.setTimeFormat(context, widget, 0.4f /* amPmRatio */, R.id.clock);
// Set up R.id.digital_appwidget_listview to use a remote views adapter
// That remote views adapter connects to a RemoteViewsService through intent.
@@ -191,118 +192,90 @@
PendingIntent.getActivity(context, 0, selectCitiesIntent, 0));
// Refresh the widget
- appWidgetManager.notifyAppWidgetViewDataChanged(
- appWidgetId, R.id.digital_appwidget_listview);
- appWidgetManager.updateAppWidget(appWidgetId, widget);
+ widgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.digital_appwidget_listview);
+ widgetManager.updateAppWidget(appWidgetId, widget);
}
private void refreshDate(Context context, RemoteViews widget, float ratio) {
if (ratio < 1) {
// The time text normally has a negative bottom margin to reduce the space between the
- // time and the date. When we scale down they overlap, so give the date a positive
+ // time and the date. When scaling down they overlap, so give the date a positive
// top padding.
final float padding = (1 - ratio) *
-context.getResources().getDimension(R.dimen.bottom_text_spacing_digital);
widget.setViewPadding(R.id.date_and_alarm, 0, (int) padding, 0, 0);
}
- // Set today's date format
+ // Set today's date format.
final Locale locale = Locale.getDefault();
final String skeleton = context.getString(R.string.abbrev_wday_abbrev_month_day_no_year);
final CharSequence timeFormat = DateFormat.getBestDateTimePattern(locale, skeleton);
widget.setCharSequence(R.id.date, "setFormat12Hour", timeFormat);
widget.setCharSequence(R.id.date, "setFormat24Hour", timeFormat);
final float fontSize = context.getResources().getDimension(R.dimen.widget_label_font_size);
- widget.setTextViewTextSize(R.id.date, TypedValue.COMPLEX_UNIT_PX, fontSize * ratio);
+ widget.setTextViewTextSize(R.id.date, COMPLEX_UNIT_PX, fontSize * ratio);
}
- protected void refreshAlarm(Context context, RemoteViews widget, float ratio) {
+ private void refreshAlarm(Context context, RemoteViews widget, float ratio) {
final String nextAlarm = Utils.getNextAlarm(context);
- if (!TextUtils.isEmpty(nextAlarm)) {
- final float fontSize =
- context.getResources().getDimension(R.dimen.widget_label_font_size);
- widget.setTextViewTextSize(
- R.id.nextAlarm, TypedValue.COMPLEX_UNIT_PX, fontSize * ratio);
+ if (TextUtils.isEmpty(nextAlarm)) {
+ widget.setViewVisibility(R.id.nextAlarm, View.GONE);
+ if (DigitalAppWidgetService.LOGGING) {
+ Log.v(TAG, "DigitalWidget hides next alarm string");
+ }
+ } else {
+ final Resources resources = context.getResources();
+ final float fontSize = resources.getDimension(R.dimen.widget_label_font_size);
+ widget.setTextViewTextSize(R.id.nextAlarm, COMPLEX_UNIT_PX, fontSize * ratio);
- int alarmDrawableResId;
+ final int alarmIconResId;
if (ratio < .72f) {
- alarmDrawableResId = R.drawable.ic_alarm_small_12dp;
+ alarmIconResId = R.drawable.ic_alarm_small_12dp;
+ } else if (ratio < .95f) {
+ alarmIconResId = R.drawable.ic_alarm_small_18dp;
+ } else {
+ alarmIconResId = R.drawable.ic_alarm_small_24dp;
}
- else if (ratio < .95f) {
- alarmDrawableResId = R.drawable.ic_alarm_small_18dp;
- }
- else {
- alarmDrawableResId = R.drawable.ic_alarm_small_24dp;
- }
- widget.setTextViewCompoundDrawablesRelative(
- R.id.nextAlarm, alarmDrawableResId, 0, 0, 0);
-
+ widget.setTextViewCompoundDrawablesRelative(R.id.nextAlarm, alarmIconResId, 0, 0, 0);
widget.setTextViewText(R.id.nextAlarm, nextAlarm);
widget.setViewVisibility(R.id.nextAlarm, View.VISIBLE);
if (DigitalAppWidgetService.LOGGING) {
Log.v(TAG, "DigitalWidget sets next alarm string to " + nextAlarm);
}
- } else {
- widget.setViewVisibility(R.id.nextAlarm, View.GONE);
- if (DigitalAppWidgetService.LOGGING) {
- Log.v(TAG, "DigitalWidget sets next alarm string to null");
- }
}
}
/**
- * Start an alarm that fires on the next quarter hour to update the world clock city
- * day when the local time or the world city crosses midnight.
- *
- * @param context The context in which the PendingIntent should perform the broadcast.
+ * Remove the existing quarter-hour callback if it is not needed (no selected cities exist).
+ * Add the quarter-hour callback if it is needed (selected cities exist).
*/
- private void startAlarmOnQuarterHour(Context context) {
- if (context != null) {
- final long onQuarterHour = Utils.getAlarmOnQuarterHour();
- final PendingIntent quarterlyIntent = getOnQuarterHourPendingIntent(context);
- final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- am.setExact(AlarmManager.RTC, onQuarterHour, quarterlyIntent);
- if (DigitalAppWidgetService.LOGGING) {
- Log.v(TAG, "startAlarmOnQuarterHour " + context.toString());
- }
+ private void updateQuarterHourCallback(Context context) {
+ if (DataModel.getDataModel().getSelectedCities().isEmpty()) {
+ // Remove the existing quarter-hour callback.
+ removeQuarterHourCallback(context);
+ return;
}
+
+ // Schedule the next quarter-hour callback; at least one city is displayed.
+ final PendingIntent pi =
+ PendingIntent.getBroadcast(context, 0, QUARTER_HOUR_INTENT, FLAG_UPDATE_CURRENT);
+ final long onQuarterHour = Utils.getAlarmOnQuarterHour();
+ getAlarmManager(context).setExact(RTC, onQuarterHour, pi);
}
-
/**
- * Remove the alarm for the quarter hour update.
- *
- * @param context The context in which the PendingIntent was started to perform the broadcast.
+ * Remove the existing quarter-hour callback.
*/
- public void cancelAlarmOnQuarterHour(Context context) {
- if (context != null) {
- PendingIntent quarterlyIntent = getOnQuarterHourPendingIntent(context);
- if (DigitalAppWidgetService.LOGGING) {
- Log.v(TAG, "cancelAlarmOnQuarterHour " + context.toString());
- }
- ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel(
- quarterlyIntent);
+ private void removeQuarterHourCallback(Context context) {
+ final PendingIntent pi =
+ PendingIntent.getBroadcast(context, 0, QUARTER_HOUR_INTENT, FLAG_NO_CREATE);
+ if (pi != null) {
+ getAlarmManager(context).cancel(pi);
+ pi.cancel();
}
}
/**
- * Create the pending intent that is broadcast on the quarter hour.
- *
- * @param context The Context in which this PendingIntent should perform the broadcast.
- * @return a pending intent with an intent unique to DigitalAppWidgetProvider
- */
- private PendingIntent getOnQuarterHourPendingIntent(Context context) {
- if (mPendingIntent == null) {
- mPendingIntent = PendingIntent.getBroadcast(context, 0,
- new Intent(ACTION_ON_QUARTER_HOUR), PendingIntent.FLAG_CANCEL_CURRENT);
- }
- return mPendingIntent;
- }
-
- /**
- * Create the component name for this class
- *
- * @param context The Context in which the widgets for this component are created
* @return the ComponentName unique to DigitalAppWidgetProvider
*/
private ComponentName getComponentName(Context context) {
@@ -311,4 +284,8 @@
}
return mComponentName;
}
-}
+
+ private static AlarmManager getAlarmManager(Context context) {
+ return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/alarmclock/DigitalWidgetViewsFactory.java b/src/com/android/alarmclock/DigitalWidgetViewsFactory.java
index e8bb776..cc7ef42 100644
--- a/src/com/android/alarmclock/DigitalWidgetViewsFactory.java
+++ b/src/com/android/alarmclock/DigitalWidgetViewsFactory.java
@@ -181,7 +181,7 @@
}
private void update(RemoteViews clock, City city, int clockId, int labelId, int dayId) {
- WidgetUtils.setTimeFormat(mContext, clock, true /* showAmPm */, clockId);
+ WidgetUtils.setTimeFormat(mContext, clock, 0.4f /* amPmRatio */, clockId);
final float fontSize = DateFormat.is24HourFormat(mContext) ? mFont24Size : mFontSize;
clock.setTextViewTextSize(clockId, TypedValue.COMPLEX_UNIT_PX, fontSize * mFontScale);
diff --git a/src/com/android/alarmclock/WidgetUtils.java b/src/com/android/alarmclock/WidgetUtils.java
index f4ce1f8..a15df7d 100644
--- a/src/com/android/alarmclock/WidgetUtils.java
+++ b/src/com/android/alarmclock/WidgetUtils.java
@@ -29,12 +29,9 @@
import com.android.deskclock.data.DataModel;
public class WidgetUtils {
- static final String TAG = "WidgetUtils";
-
public static void setClockSize(Context context, RemoteViews clock, float scale) {
- float fontSize = context.getResources().getDimension(R.dimen.widget_big_font_size);
- clock.setTextViewTextSize(
- R.id.the_clock, TypedValue.COMPLEX_UNIT_PX, fontSize * scale);
+ final float fontSize = context.getResources().getDimension(R.dimen.widget_big_font_size);
+ clock.setTextViewTextSize(R.id.clock, TypedValue.COMPLEX_UNIT_PX, fontSize * scale);
}
// Calculate the scale factor of the fonts in the widget
@@ -139,17 +136,18 @@
/***
* Set the format of the time on the clock according to the locale
- * @param context - Context used to get user's locale and time preferences
- * @param clock - view to format
- * @param showAmPm - show am/pm label if true
- * @param clockId - id of TextClock view as defined in the clock's layout.
+ * @param context Context used to get user's locale and time preferences
+ * @param clock view to format
+ * @param amPmRatio a value between 0 and 1 that is the ratio of the relative size of the
+ * am/pm string to the time string
+ * @param clockId id of TextClock view as defined in the clock's layout.
*/
- public static void setTimeFormat(Context context, RemoteViews clock, boolean showAmPm,
+ public static void setTimeFormat(Context context, RemoteViews clock, float amPmRatio,
int clockId) {
if (clock != null) {
// Set the best format for 12 hours mode according to the locale
clock.setCharSequence(clockId, "setFormat12Hour",
- Utils.get12ModeFormat(context, showAmPm));
+ Utils.get12ModeFormat(context, amPmRatio));
// Set the best format for 24 hours mode according to the locale
clock.setCharSequence(clockId, "setFormat24Hour", Utils.get24ModeFormat());
}
diff --git a/src/com/android/deskclock/AlarmClockFragment.java b/src/com/android/deskclock/AlarmClockFragment.java
index d443ba5..c78b8c8 100644
--- a/src/com/android/deskclock/AlarmClockFragment.java
+++ b/src/com/android/deskclock/AlarmClockFragment.java
@@ -16,14 +16,13 @@
package com.android.deskclock;
-import android.app.Activity;
import android.app.LoaderManager;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
-import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -31,18 +30,29 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
import com.android.deskclock.alarms.AlarmTimeClickHandler;
import com.android.deskclock.alarms.AlarmUpdateHandler;
import com.android.deskclock.alarms.ScrollHandler;
import com.android.deskclock.alarms.TimePickerCompat;
-import com.android.deskclock.alarms.dataadapter.AlarmTimeAdapter;
+import com.android.deskclock.alarms.dataadapter.AlarmItemHolder;
+import com.android.deskclock.alarms.dataadapter.CollapsedAlarmViewHolder;
+import com.android.deskclock.alarms.dataadapter.ExpandedAlarmViewHolder;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.provider.Alarm;
+import com.android.deskclock.provider.AlarmInstance;
+import com.android.deskclock.uidata.UiDataModel;
import com.android.deskclock.widget.EmptyViewController;
import com.android.deskclock.widget.toast.SnackbarManager;
import com.android.deskclock.widget.toast.ToastManager;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.deskclock.uidata.UiDataModel.Tab.ALARMS;
+
/**
* A fragment that displays a list of alarm time and allows interaction with them.
*/
@@ -57,21 +67,29 @@
// can not be found, and toast message will pop up that the alarm has be deleted.
public static final String SCROLL_TO_ALARM_INTENT_EXTRA = "deskclock.scroll.to.alarm";
+ private static final String KEY_EXPANDED_ID = "expandedId";
+
// Views
private ViewGroup mMainLayout;
private RecyclerView mRecyclerView;
// Data
private long mScrollToAlarmId = Alarm.INVALID_ID;
+ private long mExpandedAlarmId = Alarm.INVALID_ID;
private Loader mCursorLoader = null;
// Controllers
- private AlarmTimeAdapter mAlarmTimeAdapter;
+ private ItemAdapter<AlarmItemHolder> mItemAdapter;
private AlarmUpdateHandler mAlarmUpdateHandler;
private EmptyViewController mEmptyViewController;
private AlarmTimeClickHandler mAlarmTimeClickHandler;
private LinearLayoutManager mLayoutManager;
+ /** The public no-arg constructor required by all fragments. */
+ public AlarmClockFragment() {
+ super(ALARMS);
+ }
+
@Override
public void processTimeSet(int hourOfDay, int minute) {
mAlarmTimeClickHandler.processTimeSet(hourOfDay, minute);
@@ -81,6 +99,9 @@
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
mCursorLoader = getLoaderManager().initLoader(0, null, this);
+ if (savedState != null) {
+ mExpandedAlarmId = savedState.getLong(KEY_EXPANDED_ID, Alarm.INVALID_ID);
+ }
}
@Override
@@ -97,9 +118,27 @@
v.findViewById(R.id.alarms_empty_view));
mAlarmTimeClickHandler = new AlarmTimeClickHandler(this, savedState, mAlarmUpdateHandler,
this);
- mAlarmTimeAdapter = new AlarmTimeAdapter(getActivity(), savedState,
- mAlarmTimeClickHandler, this);
- mRecyclerView.setAdapter(mAlarmTimeAdapter);
+
+ mItemAdapter = new ItemAdapter<>();
+ mItemAdapter.withViewTypes(new CollapsedAlarmViewHolder.Factory(inflater),
+ null, CollapsedAlarmViewHolder.VIEW_TYPE);
+ mItemAdapter.withViewTypes(new ExpandedAlarmViewHolder.Factory(getActivity(), inflater),
+ null, ExpandedAlarmViewHolder.VIEW_TYPE);
+ mItemAdapter.setOnItemChangedListener(new ItemAdapter.OnItemChangedListener() {
+ @Override
+ public void onItemChanged(ItemAdapter.ItemHolder<?> holder) {
+ // When an alarm is expanded, collapse the currently expanded alarm.
+ if (((AlarmItemHolder) holder).isExpanded()) {
+ if (mExpandedAlarmId != Alarm.INVALID_ID &&
+ holder.itemId != mExpandedAlarmId) {
+ ((AlarmItemHolder) mItemAdapter.findItemById(mExpandedAlarmId))
+ .collapse();
+ }
+ mExpandedAlarmId = holder.itemId;
+ }
+ }
+ });
+ mRecyclerView.setAdapter(mItemAdapter);
return v;
}
@@ -108,15 +147,10 @@
public void onResume() {
super.onResume();
- final DeskClock activity = (DeskClock) getActivity();
- if (activity.getSelectedTab() == DeskClock.ALARM_TAB_INDEX) {
- setFabAppearance();
- setLeftRightButtonAppearance();
- }
-
// Check if another app asked us to create a blank new alarm.
final Intent intent = getActivity().getIntent();
if (intent.hasExtra(ALARM_CREATE_NEW_INTENT_EXTRA)) {
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
if (intent.getBooleanExtra(ALARM_CREATE_NEW_INTENT_EXTRA, false)) {
// An external app asked us to create a blank alarm.
startCreatingAlarm();
@@ -125,6 +159,8 @@
// Remove the CREATE_NEW extra now that we've processed it.
intent.removeExtra(ALARM_CREATE_NEW_INTENT_EXTRA);
} else if (intent.hasExtra(SCROLL_TO_ALARM_INTENT_EXTRA)) {
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
+
long alarmId = intent.getLongExtra(SCROLL_TO_ALARM_INTENT_EXTRA, Alarm.INVALID_ID);
if (alarmId != Alarm.INVALID_ID) {
setSmoothScrollStableId(alarmId);
@@ -148,8 +184,8 @@
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- mAlarmTimeAdapter.saveInstance(outState);
mAlarmTimeClickHandler.saveInstance(outState);
+ outState.putLong(KEY_EXPANDED_ID, mExpandedAlarmId);
}
@Override
@@ -173,15 +209,39 @@
mAlarmUpdateHandler.asyncUpdateAlarm(alarm, false, true);
}
+ public void setRingtone(Uri ringtoneUri) {
+ // Update the default ringtone for future new alarms.
+ DataModel.getDataModel().setDefaultAlarmRingtoneUri(ringtoneUri);
+
+ final Alarm alarm = mAlarmTimeClickHandler.getSelectedAlarm();
+ if (alarm == null) {
+ LogUtils.e("Could not get selected alarm to set ringtone");
+ return;
+ }
+ alarm.alert = ringtoneUri;
+ // Save the change to alarm.
+ mAlarmUpdateHandler.asyncUpdateAlarm(alarm, false /* popToast */, true /* minorUpdate */);
+ }
+
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return Alarm.getAlarmsCursorLoader(getActivity());
}
@Override
- public void onLoadFinished(Loader<Cursor> cursorLoader, final Cursor data) {
+ public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
+ final List<AlarmItemHolder> itemHolders = new ArrayList<>(data.getCount());
+ for (data.moveToFirst(); !data.isAfterLast(); data.moveToNext()) {
+ final Alarm alarm = new Alarm(data);
+ final AlarmInstance alarmInstance = alarm.canPreemptivelyDismiss()
+ ? new AlarmInstance(data, true /* joinedTable */) : null;
+ final AlarmItemHolder itemHolder =
+ new AlarmItemHolder(alarm, alarmInstance, mAlarmTimeClickHandler);
+ itemHolders.add(itemHolder);
+ }
+ mItemAdapter.setItems(itemHolders);
mEmptyViewController.setEmpty(data.getCount() == 0);
- mAlarmTimeAdapter.swapCursor(data);
+
if (mScrollToAlarmId != Alarm.INVALID_ID) {
scrollToAlarm(mScrollToAlarmId);
setSmoothScrollStableId(Alarm.INVALID_ID);
@@ -194,10 +254,10 @@
* @param alarmId The alarm id to scroll to.
*/
private void scrollToAlarm(long alarmId) {
- final int alarmCount = mAlarmTimeAdapter.getItemCount();
+ final int alarmCount = mItemAdapter.getItemCount();
int alarmPosition = -1;
for (int i = 0; i < alarmCount; i++) {
- long id = mAlarmTimeAdapter.getItemId(i);
+ long id = mItemAdapter.getItemId(i);
if (id == alarmId) {
alarmPosition = i;
break;
@@ -205,7 +265,7 @@
}
if (alarmPosition >= 0) {
- mAlarmTimeAdapter.expand(alarmPosition);
+ ((AlarmItemHolder) mItemAdapter.getItems().get(alarmPosition)).expand();
} else {
// Trying to display a deleted alarm should only happen from a missed notification for
// an alarm that has been marked deleted after use.
@@ -216,41 +276,6 @@
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
- mAlarmTimeAdapter.swapCursor(null);
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode != Activity.RESULT_OK) {
- return;
- }
-
- switch (requestCode) {
- case R.id.request_code_ringtone:
- // Extract the selected ringtone uri.
- Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
- if (uri == null) {
- uri = Alarm.NO_RINGTONE_URI;
- }
-
- // Update the default ringtone for future new alarms.
- DataModel.getDataModel().setDefaultAlarmRingtoneUri(uri);
-
- // Set the ringtone uri on the alarm.
- final Alarm alarm = mAlarmTimeClickHandler.getSelectedAlarm();
- if (alarm == null) {
- LogUtils.e("Could not get selected alarm to set ringtone");
- return;
- }
- alarm.alert = uri;
-
- // Save the change to alarm.
- mAlarmUpdateHandler.asyncUpdateAlarm(alarm, false /* popToast */,
- true /* minorUpdate */);
- break;
- default:
- LogUtils.w("Unhandled request code in onActivityResult: " + requestCode);
- }
}
@Override
@@ -259,29 +284,22 @@
}
@Override
- public void onFabClick(View view) {
+ public void onFabClick(@NonNull ImageView fab) {
mAlarmUpdateHandler.hideUndoBar();
startCreatingAlarm();
}
@Override
- public void setFabAppearance() {
- if (mFab == null || getDeskClock().getSelectedTab() != DeskClock.ALARM_TAB_INDEX) {
- return;
- }
- mFab.setVisibility(View.VISIBLE);
- mFab.setImageResource(R.drawable.ic_add_white_24dp);
- mFab.setContentDescription(getString(R.string.button_alarms));
+ public void onUpdateFab(@NonNull ImageView fab) {
+ fab.setVisibility(View.VISIBLE);
+ fab.setImageResource(R.drawable.ic_add_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.button_alarms));
}
@Override
- public void setLeftRightButtonAppearance() {
- if (mLeftButton == null || mRightButton == null ||
- getDeskClock().getSelectedTab() != DeskClock.ALARM_TAB_INDEX) {
- return;
- }
- mLeftButton.setVisibility(View.INVISIBLE);
- mRightButton.setVisibility(View.INVISIBLE);
+ public void onUpdateFabButtons(@NonNull ImageButton left, @NonNull ImageButton right) {
+ left.setVisibility(View.INVISIBLE);
+ right.setVisibility(View.INVISIBLE);
}
private void startCreatingAlarm() {
@@ -289,4 +307,4 @@
TimePickerCompat.showTimeEditDialog(this, null /* alarm */,
DateFormat.is24HourFormat(getActivity()));
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/AnalogClock.java b/src/com/android/deskclock/AnalogClock.java
index c3f0b3e..4125a6a 100644
--- a/src/com/android/deskclock/AnalogClock.java
+++ b/src/com/android/deskclock/AnalogClock.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,278 +16,198 @@
package com.android.deskclock;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.text.format.DateUtils;
-import android.text.format.Time;
+import android.os.SystemClock;
+import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
+import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.RemoteViews.RemoteView;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
import java.util.TimeZone;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+
/**
- * This widget display an analogic clock with two hands for hours and
- * minutes.
+ * This widget display an analog clock with two hands for hours and minutes.
*/
public class AnalogClock extends View {
- private Time mCalendar;
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
+ final String tz = intent.getStringExtra("time-zone");
+ mTime = Calendar.getInstance(TimeZone.getTimeZone(tz));
+ }
+ onTimeChanged();
+ }
+ };
+
+ private final Runnable mClockTick = new Runnable() {
+ @Override
+ public void run() {
+ onTimeChanged();
+
+ if (mEnableSeconds) {
+ final long now = System.currentTimeMillis();
+ final long delay = SECOND_IN_MILLIS - now % SECOND_IN_MILLIS;
+ postDelayed(this, delay);
+ }
+ }
+ };
+
+ private final Drawable mDial;
private final Drawable mHourHand;
private final Drawable mMinuteHand;
private final Drawable mSecondHand;
- private final Drawable mDial;
- private final int mDialWidth;
- private final int mDialHeight;
-
- private boolean mAttached;
-
- private final Handler mHandler = new Handler();
- private float mSeconds;
- private float mMinutes;
- private float mHour;
- private boolean mChanged;
- private final Context mContext;
- private String mTimeZoneId;
- private boolean mNoSeconds = false;
-
- private final float mDotRadius;
- private final float mDotOffset;
- private Paint mDotPaint;
+ private Calendar mTime;
+ private String mDescFormat;
+ private TimeZone mTimeZone;
+ private boolean mEnableSeconds = true;
public AnalogClock(Context context) {
- this(context, null);
+ this(context, null /* attrs */);
}
public AnalogClock(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, 0 /* defStyleAttr */);
}
- public AnalogClock(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- mContext = context;
- Resources r = mContext.getResources();
+ public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
- mDial = r.getDrawable(R.drawable.clock_analog_dial_mipmap);
- mHourHand = r.getDrawable(R.drawable.clock_analog_hour_mipmap);
- mMinuteHand = r.getDrawable(R.drawable.clock_analog_minute_mipmap);
- mSecondHand = r.getDrawable(R.drawable.clock_analog_second_mipmap);
+ mTime = Calendar.getInstance();
+ mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AnalogClock);
- mDotRadius = a.getDimension(R.styleable.AnalogClock_jewelRadius, 0);
- mDotOffset = a.getDimension(R.styleable.AnalogClock_jewelOffset, 0);
- final int dotColor = a.getColor(R.styleable.AnalogClock_jewelColor, Color.WHITE);
- if (dotColor != 0) {
- mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mDotPaint.setColor(dotColor);
- }
-
- mCalendar = new Time();
-
- mDialWidth = mDial.getIntrinsicWidth();
- mDialHeight = mDial.getIntrinsicHeight();
+ mDial = initDrawable(context, R.drawable.clock_analog_dial_mipmap);
+ mHourHand = initDrawable(context, R.drawable.clock_analog_hour_mipmap);
+ mMinuteHand = initDrawable(context, R.drawable.clock_analog_minute_mipmap);
+ mSecondHand = initDrawable(context, R.drawable.clock_analog_second_mipmap);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (!mAttached) {
- mAttached = true;
- IntentFilter filter = new IntentFilter();
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ getContext().registerReceiver(mIntentReceiver, filter);
- filter.addAction(Intent.ACTION_TIME_TICK);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-
- getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
- }
-
- // NOTE: It's safe to do these after registering the receiver since the receiver always runs
- // in the main thread, therefore the receiver can't run before this method returns.
-
- // The time zone may have changed while the receiver wasn't registered, so update the Time
- mCalendar = new Time();
-
- // Make sure we update to the current time
+ // Refresh the calendar instance since the time zone may have changed while the receiver
+ // wasn't registered.
+ mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
onTimeChanged();
- // tick the seconds
- post(mClockTick);
-
+ // Tick every second.
+ if (mEnableSeconds) {
+ mClockTick.run();
+ }
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mAttached) {
- getContext().unregisterReceiver(mIntentReceiver);
- removeCallbacks(mClockTick);
- mAttached = false;
- }
+
+ getContext().unregisterReceiver(mIntentReceiver);
+ removeCallbacks(mClockTick);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- float hScale = 1.0f;
- float vScale = 1.0f;
-
- if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) {
- hScale = (float) widthSize / (float) mDialWidth;
- }
-
- if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) {
- vScale = (float )heightSize / (float) mDialHeight;
- }
-
- float scale = Math.min(hScale, vScale);
-
- setMeasuredDimension(resolveSizeAndState((int) (mDialWidth * scale), widthMeasureSpec, 0),
- resolveSizeAndState((int) (mDialHeight * scale), heightMeasureSpec, 0));
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mChanged = true;
+ final int minWidth = Math.max(mDial.getIntrinsicWidth(), getSuggestedMinimumWidth());
+ final int minHeight = Math.max(mDial.getIntrinsicHeight(), getSuggestedMinimumHeight());
+ setMeasuredDimension(getDefaultSize(minWidth, widthMeasureSpec),
+ getDefaultSize(minHeight, heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- boolean changed = mChanged;
- if (changed) {
- mChanged = false;
+ final int w = getWidth();
+ final int h = getHeight();
+
+ final int saveCount = canvas.save();
+
+ // Center the canvas at the mid-point.
+ canvas.translate(w / 2, h / 2);
+
+ // Scale down the clock if necessary.
+ final float scale = Math.min((float) w / mDial.getIntrinsicWidth(),
+ (float) h / mDial.getIntrinsicHeight());
+ if (scale < 1f) {
+ canvas.scale(scale, scale, 0f, 0f);
}
- int availableWidth = getWidth();
- int availableHeight = getHeight();
+ mDial.draw(canvas);
- int x = availableWidth / 2;
- int y = availableHeight / 2;
+ final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
+ canvas.rotate(hourAngle, 0f, 0f);
+ mHourHand.draw(canvas);
- final Drawable dial = mDial;
- int w = dial.getIntrinsicWidth();
- int h = dial.getIntrinsicHeight();
+ final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
+ canvas.rotate(minuteAngle - hourAngle, 0f, 0f);
+ mMinuteHand.draw(canvas);
- boolean scaled = false;
-
- if (availableWidth < w || availableHeight < h) {
- scaled = true;
- float scale = Math.min((float) availableWidth / (float) w,
- (float) availableHeight / (float) h);
- canvas.save();
- canvas.scale(scale, scale, x, y);
+ if (mEnableSeconds) {
+ final float secondAngle = mTime.get(Calendar.SECOND) * 6f;
+ canvas.rotate(secondAngle - minuteAngle, 0f, 0f);
+ mSecondHand.draw(canvas);
}
- if (changed) {
- dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
- }
- dial.draw(canvas);
-
- if (mDotRadius > 0f && mDotPaint != null) {
- canvas.drawCircle(x, y - (h / 2) + mDotOffset, mDotRadius, mDotPaint);
- }
-
- drawHand(canvas, mHourHand, x, y, mHour / 12.0f * 360.0f, changed);
- drawHand(canvas, mMinuteHand, x, y, mMinutes / 60.0f * 360.0f, changed);
- if (!mNoSeconds) {
- drawHand(canvas, mSecondHand, x, y, mSeconds / 60.0f * 360.0f, changed);
- }
-
- if (scaled) {
- canvas.restore();
- }
+ canvas.restoreToCount(saveCount);
}
- private void drawHand(Canvas canvas, Drawable hand, int x, int y, float angle,
- boolean changed) {
- canvas.save();
- canvas.rotate(angle, x, y);
- if (changed) {
- final int w = hand.getIntrinsicWidth();
- final int h = hand.getIntrinsicHeight();
- hand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
- }
- hand.draw(canvas);
- canvas.restore();
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return mDial == who
+ || mHourHand == who
+ || mMinuteHand == who
+ || mSecondHand == who
+ || super.verifyDrawable(who);
+ }
+
+ private Drawable initDrawable(Context context, @DrawableRes int id) {
+ final Drawable d = ContextCompat.getDrawable(context, id);
+
+ // Center the drawable using its bounds.
+ final int midX = d.getIntrinsicWidth() / 2;
+ final int midY = d.getIntrinsicHeight() / 2;
+ d.setBounds(-midX, -midY, midX, midY);
+
+ // Register callback to support non-bitmap drawables.
+ d.setCallback(this);
+
+ return d;
}
private void onTimeChanged() {
- mCalendar.setToNow();
-
- if (mTimeZoneId != null) {
- mCalendar.switchTimezone(mTimeZoneId);
- }
-
- int hour = mCalendar.hour;
- int minute = mCalendar.minute;
- int second = mCalendar.second;
- // long millis = System.currentTimeMillis() % 1000;
-
- mSeconds = second;//(float) ((second * 1000 + millis) / 166.666);
- mMinutes = minute + second / 60.0f;
- mHour = hour + mMinutes / 60.0f;
- mChanged = true;
-
- updateContentDescription(mCalendar);
- }
-
- private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- String tz = intent.getStringExtra("time-zone");
- mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
- }
- onTimeChanged();
- invalidate();
- }
- };
-
- private final Runnable mClockTick = new Runnable () {
-
- @Override
- public void run() {
- onTimeChanged();
- invalidate();
- AnalogClock.this.postDelayed(mClockTick, 1000);
- }
- };
-
- private void updateContentDescription(Time time) {
- final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
- String contentDescription = DateUtils.formatDateTime(mContext,
- time.toMillis(false), flags);
- setContentDescription(contentDescription);
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ setContentDescription(DateFormat.format(mDescFormat, mTime));
+ invalidate();
}
public void setTimeZone(String id) {
- mTimeZoneId = id;
+ mTimeZone = TimeZone.getTimeZone(id);
+ mTime.setTimeZone(mTimeZone);
onTimeChanged();
}
public void enableSeconds(boolean enable) {
- mNoSeconds = !enable;
+ mEnableSeconds = enable;
+ if (mEnableSeconds) {
+ mClockTick.run();
+ }
}
-
}
-
diff --git a/src/com/android/deskclock/AnimatorUtils.java b/src/com/android/deskclock/AnimatorUtils.java
index 26d266f..0794cf8 100644
--- a/src/com/android/deskclock/AnimatorUtils.java
+++ b/src/com/android/deskclock/AnimatorUtils.java
@@ -19,6 +19,7 @@
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
@@ -87,7 +88,8 @@
}
};
- public static final ArgbEvaluator ARGB_EVALUATOR = new ArgbEvaluator();
+ @SuppressWarnings("unchecked")
+ public static final TypeEvaluator<Integer> ARGB_EVALUATOR = new ArgbEvaluator();
private static Method sAnimateValue;
private static boolean sTryAnimateValue = true;
@@ -143,4 +145,8 @@
PropertyValuesHolder.ofFloat(View.SCALE_X, values),
PropertyValuesHolder.ofFloat(View.SCALE_Y, values));
}
+
+ public static ValueAnimator getAlphaAnimator(View view, float... values) {
+ return ObjectAnimator.ofFloat(view, View.ALPHA, values);
+ }
}
diff --git a/src/com/android/deskclock/AsyncRingtonePlayer.java b/src/com/android/deskclock/AsyncRingtonePlayer.java
index 59eb01c..00240ed 100644
--- a/src/com/android/deskclock/AsyncRingtonePlayer.java
+++ b/src/com/android/deskclock/AsyncRingtonePlayer.java
@@ -1,5 +1,6 @@
package com.android.deskclock;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
@@ -12,6 +13,7 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
@@ -70,7 +72,7 @@
/**
* @param crescendoPrefKey the key to the user preference that defines the crescendo behavior
- * associated with this ringtone player
+ * associated with this ringtone player, or null to ignore crescendo
*/
public AsyncRingtonePlayer(Context context, String crescendoPrefKey) {
mContext = context;
@@ -127,6 +129,7 @@
/**
* Creates a new ringtone Handler running in its own thread.
*/
+ @SuppressLint("HandlerLeak")
private Handler getNewHandler() {
final HandlerThread thread = new HandlerThread("ringtone-player");
thread.start();
@@ -213,10 +216,11 @@
}
/**
- * @return {@code true} iff the crescendo duration is more than 0 seconds
+ * Returns true if the crescendo preference was given and the duration is more than
+ * 0 seconds.
*/
private boolean isCrescendoEnabled(Context context) {
- return getCrescendoDurationMillis(context) > 0;
+ return mCrescendoPrefKey != null && getCrescendoDurationMillis(context) > 0;
}
/**
@@ -326,7 +330,7 @@
// Compute the time at which the crescendo will stop.
mCrescendoDuration = getCrescendoDurationMillis(context);
- mCrescendoStopTime = System.currentTimeMillis() + mCrescendoDuration;
+ mCrescendoStopTime = now() + mCrescendoDuration;
scheduleVolumeAdjustment = true;
}
@@ -416,7 +420,7 @@
}
// If the crescendo is complete set the volume to the maximum; we're done.
- final long currentTime = System.currentTimeMillis();
+ final long currentTime = now();
if (currentTime > mCrescendoStopTime) {
mCrescendoDuration = 0;
mCrescendoStopTime = 0;
@@ -533,7 +537,7 @@
// Compute the time at which the crescendo will stop.
mCrescendoDuration = getCrescendoDurationMillis(context);
- mCrescendoStopTime = System.currentTimeMillis() + mCrescendoDuration;
+ mCrescendoStopTime = now() + mCrescendoDuration;
scheduleVolumeAdjustment = true;
}
@@ -597,7 +601,7 @@
}
// If the crescendo is complete set the volume to the maximum; we're done.
- final long currentTime = System.currentTimeMillis();
+ final long currentTime = now();
if (currentTime > mCrescendoStopTime) {
mCrescendoDuration = 0;
mCrescendoStopTime = 0;
@@ -612,5 +616,12 @@
return true;
}
}
+
+ /**
+ * @return the current elapsed time which is immune to device time changes
+ */
+ private static long now() {
+ return SystemClock.elapsedRealtime();
+ }
}
diff --git a/src/com/android/deskclock/BaseActivity.java b/src/com/android/deskclock/BaseActivity.java
index 4b72d80..04c6280 100644
--- a/src/com/android/deskclock/BaseActivity.java
+++ b/src/com/android/deskclock/BaseActivity.java
@@ -29,7 +29,7 @@
* Base activity class that changes with window's background color dynamically based on the
* current hour.
*/
-public class BaseActivity extends AppCompatActivity {
+public abstract class BaseActivity extends AppCompatActivity {
/**
* Key used to save/restore the current background color from the saved instance state.
diff --git a/src/com/android/deskclock/ClockFragment.java b/src/com/android/deskclock/ClockFragment.java
index c9b339f..a48bdb8 100644
--- a/src/com/android/deskclock/ClockFragment.java
+++ b/src/com/android/deskclock/ClockFragment.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
+import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -34,6 +35,8 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextClock;
import android.widget.TextView;
@@ -50,6 +53,7 @@
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.deskclock.uidata.UiDataModel.Tab.CLOCKS;
import static java.util.Calendar.DAY_OF_WEEK;
/**
@@ -76,7 +80,9 @@
private String mDateFormatForAccessibility;
/** The public no-arg constructor required by all fragments. */
- public ClockFragment() {}
+ public ClockFragment() {
+ super(CLOCKS);
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -134,8 +140,6 @@
super.onResume();
final Activity activity = getActivity();
- setFabAppearance();
- setLeftRightButtonAppearance();
mDateFormat = getString(R.string.abbrev_wday_month_day_no_year);
mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year);
@@ -147,7 +151,9 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
+ if (Utils.isLOrLater()) {
+ filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
+ }
activity.registerReceiver(mBroadcastReceiver, filter);
// Resume can be invoked after changing the clock style.
@@ -162,7 +168,9 @@
refreshDates();
refreshAlarm();
+ // Alarm observer is null on L or later.
if (mAlarmObserver != null) {
+ @SuppressWarnings("deprecation")
final Uri uri = Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED);
activity.getContentResolver().registerContentObserver(uri, false, mAlarmObserver);
}
@@ -181,34 +189,21 @@
}
@Override
- public void onFabClick(View view) {
+ public void onFabClick(@NonNull ImageView fab) {
startActivity(new Intent(getActivity(), CitySelectionActivity.class));
}
@Override
- public void setFabAppearance() {
- if (mFab == null || getSelectedTab() != DeskClock.CLOCK_TAB_INDEX) {
- return;
- }
-
- mFab.setVisibility(VISIBLE);
- mFab.setImageResource(R.drawable.ic_language_white_24dp);
- mFab.setContentDescription(getString(R.string.button_cities));
+ public void onUpdateFab(@NonNull ImageView fab) {
+ fab.setVisibility(VISIBLE);
+ fab.setImageResource(R.drawable.ic_language_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.button_cities));
}
@Override
- public void setLeftRightButtonAppearance() {
- if (getSelectedTab() != DeskClock.CLOCK_TAB_INDEX) {
- return;
- }
-
- if (mLeftButton != null) {
- mLeftButton.setVisibility(INVISIBLE);
- }
-
- if (mRightButton != null) {
- mRightButton.setVisibility(INVISIBLE);
- }
+ public void onUpdateFabButtons(@NonNull ImageButton left, @NonNull ImageButton right) {
+ left.setVisibility(INVISIBLE);
+ right.setVisibility(INVISIBLE);
}
/**
@@ -380,10 +375,12 @@
analogClock.setTimeZone(city.getTimeZoneId());
analogClock.enableSeconds(false);
} else {
- digitalClock.setVisibility(VISIBLE);
analogClock.setVisibility(GONE);
+ digitalClock.setVisibility(VISIBLE);
digitalClock.setTimeZone(city.getTimeZoneId());
- Utils.setTimeFormat(mContext, digitalClock);
+ digitalClock.setFormat12Hour(
+ Utils.get12ModeFormat(mContext, 0.22f /* amPmRatio */));
+ digitalClock.setFormat24Hour(Utils.get24ModeFormat());
}
// Bind the city name.
diff --git a/src/com/android/deskclock/DeskClock.java b/src/com/android/deskclock/DeskClock.java
index e0189a0..2f59f9a 100644
--- a/src/com/android/deskclock/DeskClock.java
+++ b/src/com/android/deskclock/DeskClock.java
@@ -16,21 +16,23 @@
package com.android.deskclock;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
-import android.media.AudioManager;
+import android.net.Uri;
import android.os.Bundle;
-import android.support.annotation.VisibleForTesting;
import android.support.design.widget.TabLayout;
-import android.support.design.widget.TabLayout.Tab;
import android.support.design.widget.TabLayout.ViewPagerOnTabSelectedListener;
import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
-import android.util.ArraySet;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -47,41 +49,64 @@
import com.android.deskclock.data.DataModel;
import com.android.deskclock.events.Events;
import com.android.deskclock.provider.Alarm;
-import com.android.deskclock.stopwatch.StopwatchFragment;
-import com.android.deskclock.timer.TimerFragment;
+import com.android.deskclock.uidata.TabListener;
+import com.android.deskclock.uidata.UiDataModel;
+import com.android.deskclock.uidata.UiDataModel.Tab;
import com.android.deskclock.widget.RtlViewPager;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_DRAGGING;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_IDLE;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_SETTLING;
+import static com.android.deskclock.AnimatorUtils.getAlphaAnimator;
+import static com.android.deskclock.AnimatorUtils.getScaleAnimator;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_AND_BUTTONS_IMMEDIATE;
/**
- * DeskClock clock view for desk docks.
+ * The main activity of the application which displays 4 different tabs contains alarms, world
+ * clocks, timers and a stopwatch.
*/
public class DeskClock extends BaseActivity
- implements LabelDialogFragment.AlarmLabelDialogHandler {
+ implements FabContainer, LabelDialogFragment.AlarmLabelDialogHandler,
+ RingtonePickerDialogFragment.RingtoneSelectionListener {
- private static final String TAG = "DeskClock";
+ /** Models the interesting state of display the {@link #mFab} button may inhabit. */
+ private enum FabState { SHOWING, HIDE_ARMED, HIDING }
- // Alarm action for midnight (so we can update the date display).
- private static final String KEY_SELECTED_TAB = "selected_tab";
- public static final String SELECT_TAB_INTENT_EXTRA = "deskclock.select.tab";
+ /** Coordinates handling of context menu items. */
+ private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager();
- public static final int ALARM_TAB_INDEX = 0;
- public static final int CLOCK_TAB_INDEX = 1;
- public static final int TIMER_TAB_INDEX = 2;
- public static final int STOPWATCH_TAB_INDEX = 3;
+ /** Shrinks the {@link #mFab}, {@link #mLeftButton} and {@link #mRightButton} to nothing. */
+ private final AnimatorSet mHideAnimation = new AnimatorSet();
- private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager(this);
+ /** Grows the {@link #mFab}, {@link #mLeftButton} and {@link #mRightButton} to natural sizes. */
+ private final AnimatorSet mShowAnimation = new AnimatorSet();
- private TabLayout mTabLayout;
- private RtlViewPager mViewPager;
+ /** Hides, updates, and shows only the {@link #mFab}; the buttons are untouched. */
+ private final AnimatorSet mUpdateFabOnlyAnimation = new AnimatorSet();
+
+ /** Automatically starts the {@link #mShowAnimation} after {@link #mHideAnimation} ends. */
+ private final AnimatorListenerAdapter mAutoStartShowListener = new AutoStartShowListener();
+
+ /** The current display state of the {@link #mFab}. */
+ private FabState mFabState = FabState.SHOWING;
+
+ /** The single floating-action button shared across all tabs in the user interface. */
private ImageView mFab;
+
+ /** The button left of the {@link #mFab} shared across all tabs in the user interface. */
private ImageButton mLeftButton;
+
+ /** The button right of the {@link #mFab} shared across all tabs in the user interface. */
private ImageButton mRightButton;
- private TabsAdapter mTabsAdapter;
- private int mSelectedTab;
+ /** The ViewPager that pages through the fragments representing the content of the tabs. */
+ private RtlViewPager mFragmentTabPager;
+
+ /** Generates the fragments that are displayed by the {@link #mFragmentTabPager}. */
+ private TabFragmentAdapter mFragmentTabPagerAdapter;
+
+ /** The container that stores the tab headers. */
+ private TabLayout mTabLayout;
/** {@code true} when a settings change necessitates recreating this activity. */
private boolean mRecreateActivity;
@@ -89,112 +114,29 @@
@Override
public void onNewIntent(Intent newIntent) {
super.onNewIntent(newIntent);
- LogUtils.d(TAG, "onNewIntent with intent: %s", newIntent);
- // update our intent so that we can consult it to determine whether or
- // not the most recent launch was via a dock event
+ // Fragments may query the latest intent for information, so update the intent.
setIntent(newIntent);
-
- // Honor the tab requested by the intent, if any.
- int tab = newIntent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
- if (tab != -1 && mTabLayout != null) {
- mTabLayout.getTabAt(tab).select();
- mViewPager.setCurrentItem(tab);
- }
- }
-
- @VisibleForTesting
- DeskClockFragment getSelectedFragment() {
- return (DeskClockFragment) mTabsAdapter.getItem(mSelectedTab);
- }
-
- private void createTabs() {
- final TabLayout.Tab alarmTab = mTabLayout.newTab();
- alarmTab.setIcon(R.drawable.ic_tab_alarm).setContentDescription(R.string.menu_alarm);
- mTabsAdapter.addTab(alarmTab, AlarmClockFragment.class, ALARM_TAB_INDEX);
-
- final Tab clockTab = mTabLayout.newTab();
- clockTab.setIcon(R.drawable.ic_tab_clock).setContentDescription(R.string.menu_clock);
- mTabsAdapter.addTab(clockTab, ClockFragment.class, CLOCK_TAB_INDEX);
-
- final Tab timerTab = mTabLayout.newTab();
- timerTab.setIcon(R.drawable.ic_tab_timer).setContentDescription(R.string.menu_timer);
- mTabsAdapter.addTab(timerTab, TimerFragment.class, TIMER_TAB_INDEX);
-
- final Tab stopwatchTab = mTabLayout.newTab();
- stopwatchTab.setIcon(R.drawable.ic_tab_stopwatch)
- .setContentDescription(R.string.menu_stopwatch);
- mTabsAdapter.addTab(stopwatchTab, StopwatchFragment.class, STOPWATCH_TAB_INDEX);
-
- mTabLayout.getTabAt(mSelectedTab).select();
- mViewPager.setCurrentItem(mSelectedTab);
- mTabsAdapter.notifySelectedPage(mSelectedTab);
}
@Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setVolumeControlStream(AudioManager.STREAM_ALARM);
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- if (icicle != null) {
- mSelectedTab = icicle.getInt(KEY_SELECTED_TAB, CLOCK_TAB_INDEX);
- } else {
- mSelectedTab = CLOCK_TAB_INDEX;
-
+ if (savedInstanceState == null) {
// Set the background color to initially match the theme value so that we can
// smoothly transition to the dynamic color.
- setBackgroundColor(getResources().getColor(R.color.default_background),
- false /* animate */);
- }
-
- // Honor the tab requested by the intent, if any.
- final Intent intent = getIntent();
- if (intent != null) {
- int tab = intent.getIntExtra(SELECT_TAB_INTENT_EXTRA, -1);
- if (tab != -1) {
- mSelectedTab = tab;
- }
+ final int backgroundColor = ContextCompat.getColor(this, R.color.default_background);
+ setBackgroundColor(backgroundColor, false /* animate */);
}
setContentView(R.layout.desk_clock);
+
+ // Configure the toolbar.
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
- mTabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
- mFab = (ImageView) findViewById(R.id.fab);
- mLeftButton = (ImageButton) findViewById(R.id.left_button);
- mRightButton = (ImageButton) findViewById(R.id.right_button);
- if (mTabsAdapter == null) {
- mViewPager = (RtlViewPager) findViewById(R.id.desk_clock_pager);
- // Keep all four tabs to minimize jank.
- mViewPager.setOffscreenPageLimit(3);
- // Set Accessibility Delegate to null so ViewPager doesn't intercept movements and
- // prevent the fab from being selected.
- mViewPager.setAccessibilityDelegate(null);
- mTabsAdapter = new TabsAdapter(this, mViewPager);
- createTabs();
- mTabLayout.setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(mViewPager));
- }
- mFab.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- getSelectedFragment().onFabClick(view);
- }
- });
- mLeftButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- getSelectedFragment().onLeftButtonClick(view);
- }
- });
- mRightButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- getSelectedFragment().onRightButtonClick(view);
- }
- });
-
- // Configure the menu item controllers.
+ // Configure the menu item controllers add behavior to the toolbar.
mActionBarMenuManager
.addMenuItemController(new SettingMenuItemController(this))
.addMenuItemController(new NightModeMenuItemController(this))
@@ -205,8 +147,87 @@
// inflation occurs *after* the initial draw and a second layout pass adds in the menu.
onCreateOptionsMenu(toolbar.getMenu());
- // We need to update the system next alarm time on app startup because the
- // user might have clear our data.
+ // Create the tabs that make up the user interface.
+ mTabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
+ for (int i = 0; i < UiDataModel.getUiDataModel().getTabCount(); i++) {
+ final Tab tab = UiDataModel.getUiDataModel().getTab(i);
+ mTabLayout.addTab(mTabLayout.newTab()
+ .setIcon(tab.getIconId())
+ .setContentDescription(tab.getContentDescriptionId()));
+ }
+
+ // Configure the buttons shared by the tabs.
+ mFab = (ImageView) findViewById(R.id.fab);
+ mLeftButton = (ImageButton) findViewById(R.id.left_button);
+ mRightButton = (ImageButton) findViewById(R.id.right_button);
+
+ mFab.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ getSelectedDeskClockFragment().onFabClick(mFab);
+ }
+ });
+ mLeftButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ getSelectedDeskClockFragment().onLeftButtonClick(mLeftButton);
+ }
+ });
+ mRightButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ getSelectedDeskClockFragment().onRightButtonClick(mRightButton);
+ }
+ });
+
+ // Build the reusable animations that hide and show the fab and left/right buttons.
+ // These may be used independently or be chained together.
+ final long duration = UiDataModel.getUiDataModel().getShortAnimationDuration();
+ mHideAnimation
+ .setDuration(duration)
+ .play(getScaleAnimator(mFab, 1f, 0f))
+ .with(getAlphaAnimator(mLeftButton, 1f, 0f))
+ .with(getAlphaAnimator(mRightButton, 1f, 0f));
+
+ mShowAnimation
+ .setDuration(duration)
+ .play(getScaleAnimator(mFab, 0f, 1f))
+ .with(getAlphaAnimator(mLeftButton, 0f, 1f))
+ .with(getAlphaAnimator(mRightButton, 0f, 1f));
+
+ // Build the reusable animation that hides and shows only the fab.
+ final ValueAnimator hideFabAnimation = getScaleAnimator(mFab, 1f, 0f);
+ hideFabAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ getSelectedDeskClockFragment().onUpdateFab(mFab);
+ }
+ });
+ final ValueAnimator showFabAnimation = getScaleAnimator(mFab, 0f, 1f);
+ mUpdateFabOnlyAnimation
+ .setDuration(duration)
+ .play(showFabAnimation)
+ .after(hideFabAnimation);
+
+ // Customize the view pager.
+ mFragmentTabPagerAdapter = new TabFragmentAdapter(this);
+ mFragmentTabPager = (RtlViewPager) findViewById(R.id.desk_clock_pager);
+ // Keep all four tabs to minimize jank.
+ mFragmentTabPager.setOffscreenPageLimit(3);
+ // Set Accessibility Delegate to null so view pager doesn't intercept movements and
+ // prevent the fab from being selected.
+ mFragmentTabPager.setAccessibilityDelegate(null);
+ // Mirror changes made to the selected page of the view pager into UiDataModel.
+ mFragmentTabPager.setOnRTLPageChangeListener(new PageChangeWatcher());
+ mFragmentTabPager.setAdapter(mFragmentTabPagerAdapter);
+
+ // Selecting a tab implicitly selects a page in the view pager.
+ mTabLayout.setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(mFragmentTabPager));
+
+ // Honor changes to the selected tab from outside entities.
+ UiDataModel.getUiDataModel().addTabListener(new TabChangeWatcher());
+
+ // Update the next alarm time on app startup because the user might have altered the data.
AlarmStateManager.updateNextAlarm(this);
}
@@ -214,6 +235,9 @@
protected void onResume() {
super.onResume();
DataModel.getDataModel().setApplicationInForeground(true);
+
+ // Honor the selected tab in case it changed while the app was paused.
+ updateCurrentTab(UiDataModel.getUiDataModel().getSelectedTabIndex());
}
@Override
@@ -225,7 +249,7 @@
// A runnable must be posted here or the new DeskClock activity will be recreated in a
// paused state, even though it is the foreground activity.
- mViewPager.post(new Runnable() {
+ mFragmentTabPager.post(new Runnable() {
@Override
public void run() {
recreate();
@@ -241,12 +265,6 @@
}
@Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt(KEY_SELECTED_TAB, mTabLayout.getSelectedTabPosition());
- }
-
- @Override
public boolean onCreateOptionsMenu(Menu menu) {
mActionBarMenuManager.createOptionsMenu(menu, getMenuInflater());
return true;
@@ -261,10 +279,56 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (mActionBarMenuManager.handleMenuItemClick(item)) {
- return true;
+ return mActionBarMenuManager.handleMenuItemClick(item) || super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * Called by the LabelDialogFormat class after the dialog is finished.
+ */
+ @Override
+ public void onDialogLabelSet(Alarm alarm, String label, String tag) {
+ final Fragment frag = getFragmentManager().findFragmentByTag(tag);
+ if (frag instanceof AlarmClockFragment) {
+ ((AlarmClockFragment) frag).setLabel(alarm, label);
}
- return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * Called by the RingtonePickerDialogFragment class after the dialog is finished.
+ */
+ @Override
+ public void onRingtoneSelected(Uri ringtoneUri, String fragmentTag) {
+ final Fragment frag = getFragmentManager().findFragmentByTag(fragmentTag);
+ if (frag instanceof AlarmClockFragment) {
+ ((AlarmClockFragment) frag).setRingtone(ringtoneUri);
+ }
+ }
+
+ @Override
+ public void updateFab(UpdateType updateType) {
+ switch (updateType) {
+ case DISABLE_BUTTONS:
+ mLeftButton.setEnabled(false);
+ mRightButton.setEnabled(false);
+ break;
+
+ case FAB_AND_BUTTONS_IMMEDIATE:
+ final DeskClockFragment f = getSelectedDeskClockFragment();
+ f.onUpdateFab(mFab);
+ f.onUpdateFabButtons(mLeftButton, mRightButton);
+ break;
+
+ case FAB_ONLY_ANIMATED:
+ mUpdateFabOnlyAnimation.start();
+ break;
+
+ case FAB_AND_BUTTONS_ANIMATED:
+ // Ensure there is never more than one mAutoStartShowListener registered.
+ mHideAnimation.removeListener(mAutoStartShowListener);
+ mHideAnimation.addListener(mAutoStartShowListener);
+ mHideAnimation.start();
+ break;
+ }
}
@Override
@@ -276,196 +340,193 @@
}
}
- public void registerPageChangedListener(DeskClockFragment frag) {
- if (mTabsAdapter != null) {
- mTabsAdapter.registerPageChangedListener(frag);
+ /**
+ * Configure the {@link #mFragmentTabPager} and {@link #mTabLayout} to display the tab at the
+ * given {@code index}.
+ *
+ * @param index the index of the page to display
+ */
+ private void updateCurrentTab(int index) {
+ final TabLayout.Tab tab = mTabLayout.getTabAt(index);
+ if (tab != null && !tab.isSelected()) {
+ tab.select();
+ }
+ if (mFragmentTabPager.getCurrentItem() != index) {
+ mFragmentTabPager.setCurrentItem(index);
}
}
- public void unregisterPageChangedListener(DeskClockFragment frag) {
- if (mTabsAdapter != null) {
- mTabsAdapter.unregisterPageChangedListener(frag);
- }
+ private DeskClockFragment getSelectedDeskClockFragment() {
+ final int index = UiDataModel.getUiDataModel().getSelectedTabIndex();
+ return (DeskClockFragment) mFragmentTabPagerAdapter.getItem(index);
}
/**
- * Adapter for wrapping together the ActionBar's tab with the ViewPager
+ * As the view pager changes the selected page, update the model to record the new selected tab.
*/
- private class TabsAdapter extends FragmentPagerAdapter implements OnPageChangeListener {
+ private class PageChangeWatcher implements OnPageChangeListener {
- private static final String KEY_TAB_POSITION = "tab_position";
+ /** The last reported page scroll state; used to detect exotic state changes. */
+ private int mPriorState = SCROLL_STATE_IDLE;
- final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
-
- TabInfo(Class<?> _class, int position) {
- clss = _class;
- args = new Bundle();
- args.putInt(KEY_TAB_POSITION, position);
- }
-
- public int getPosition() {
- return args.getInt(KEY_TAB_POSITION, 0);
- }
- }
-
- private final List<TabInfo> mTabs = new ArrayList<>(4 /* number of fragments */);
- private final Context mContext;
- private final RtlViewPager mPager;
- // Used for doing callbacks to fragments.
- private final Set<String> mFragmentTags = new ArraySet<>(4 /* number of fragments */);
-
- public TabsAdapter(AppCompatActivity activity, RtlViewPager pager) {
- super(activity.getFragmentManager());
- mContext = activity;
- mPager = pager;
- mPager.setAdapter(this);
- mPager.setOnRTLPageChangeListener(this);
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- return super.instantiateItem(container, mViewPager.getRtlAwareIndex(position));
- }
-
- @Override
- public Fragment getItem(int position) {
- // Because this public method is called outside many times,
- // check if it exits first before creating a new one.
- final String name = makeFragmentName(R.id.desk_clock_pager, position);
- Fragment fragment = getFragmentManager().findFragmentByTag(name);
- if (fragment == null) {
- TabInfo info = mTabs.get(position);
- fragment = Fragment.instantiate(mContext, info.clss.getName(), info.args);
- if (fragment instanceof TimerFragment) {
- ((TimerFragment) fragment).setFabAppearance();
- ((TimerFragment) fragment).setLeftRightButtonAppearance();
- }
- }
- return fragment;
- }
-
- /**
- * Copied from:
- * android/frameworks/support/v13/java/android/support/v13/app/FragmentPagerAdapter.java#94
- * Create unique name for the fragment so fragment manager knows it exist.
- */
- private String makeFragmentName(int viewId, int index) {
- return "android:switcher:" + viewId + ":" + index;
- }
-
- @Override
- public int getCount() {
- return mTabs.size();
- }
-
- public void addTab(TabLayout.Tab tab, Class<?> clss, int position) {
- TabInfo info = new TabInfo(clss, position);
- mTabs.add(info);
- mTabLayout.addTab(tab);
- notifyDataSetChanged();
- }
-
- @Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- // Do nothing
- }
-
- @Override
- public void onPageSelected(int position) {
- // Set the page before doing the menu so that onCreateOptionsMenu knows what page it is.
- mTabLayout.getTabAt(position).select();
- notifyPageChanged(position);
-
- mSelectedTab = position;
-
- // Avoid sending events for the initial tab selection on launch and the reselecting a
- // tab after a configuration change.
- if (DataModel.getDataModel().isApplicationInForeground()) {
- switch (mSelectedTab) {
- case ALARM_TAB_INDEX:
- Events.sendAlarmEvent(R.string.action_show, R.string.label_deskclock);
- break;
- case CLOCK_TAB_INDEX:
- Events.sendClockEvent(R.string.action_show, R.string.label_deskclock);
- break;
- case TIMER_TAB_INDEX:
- Events.sendTimerEvent(R.string.action_show, R.string.label_deskclock);
- break;
- case STOPWATCH_TAB_INDEX:
- Events.sendStopwatchEvent(R.string.action_show, R.string.label_deskclock);
- break;
- }
- }
-
- final DeskClockFragment f = (DeskClockFragment) getItem(position);
- if (f != null) {
- f.setFabAppearance();
- f.setLeftRightButtonAppearance();
+ // Only hide the fab when a non-zero drag distance is detected. This prevents
+ // over-scrolling from needlessly hiding the fab.
+ if (mFabState == FabState.HIDE_ARMED && positionOffsetPixels != 0) {
+ mFabState = FabState.HIDING;
+ mHideAnimation.start();
}
}
@Override
public void onPageScrollStateChanged(int state) {
- // Do nothing
- }
+ if (mPriorState == SCROLL_STATE_IDLE && state == SCROLL_STATE_SETTLING) {
+ // The user has tapped a tab button; play the hide and show animations linearly.
+ mHideAnimation.addListener(mAutoStartShowListener);
+ mHideAnimation.start();
+ mFabState = FabState.HIDING;
- public void notifySelectedPage(int page) {
- notifyPageChanged(page);
- }
-
- private void notifyPageChanged(int newPage) {
- for (String tag : mFragmentTags) {
- final FragmentManager fm = getFragmentManager();
- DeskClockFragment f = (DeskClockFragment) fm.findFragmentByTag(tag);
- if (f != null) {
- f.onPageChanged(newPage);
+ } else if (mPriorState == SCROLL_STATE_SETTLING && state == SCROLL_STATE_DRAGGING) {
+ // The user has interrupted settling on a tab and the fab button must be re-hidden.
+ if (mShowAnimation.isStarted()) {
+ mShowAnimation.cancel();
}
+ if (mHideAnimation.isStarted()) {
+ // Let the hide animation finish naturally; don't auto show when it ends.
+ mHideAnimation.removeListener(mAutoStartShowListener);
+ } else {
+ // Start and immediately end the hide animation to jump to the hidden state.
+ mHideAnimation.start();
+ mHideAnimation.end();
+ }
+ mFabState = FabState.HIDING;
+
+ } else if (state != SCROLL_STATE_DRAGGING && mFabState == FabState.HIDING) {
+ // The user has lifted their finger; show the buttons now or after hide ends.
+ if (mHideAnimation.isStarted()) {
+ // Finish the hide animation and then start the show animation.
+ mHideAnimation.addListener(mAutoStartShowListener);
+ } else {
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
+ mShowAnimation.start();
+
+ // The animation to show the fab has begun; update the state to showing.
+ mFabState = FabState.SHOWING;
+ }
+ } else if (state == SCROLL_STATE_DRAGGING) {
+ // The user has started a drag so arm the hide animation.
+ mFabState = FabState.HIDE_ARMED;
}
+
+ // Update the last known state.
+ mPriorState = state;
}
- public void registerPageChangedListener(DeskClockFragment frag) {
- String tag = frag.getTag();
- if (mFragmentTags.contains(tag)) {
- LogUtils.wtf(TAG, "Trying to add an existing fragment " + tag);
- } else {
- mFragmentTags.add(frag.getTag());
- }
- // Since registering a listener by the fragment is done sometimes after the page
- // was already changed, make sure the fragment gets the current page
- frag.onPageChanged(mTabLayout.getSelectedTabPosition());
- }
-
- public void unregisterPageChangedListener(DeskClockFragment frag) {
- mFragmentTags.remove(frag.getTag());
+ @Override
+ public void onPageSelected(int position) {
+ UiDataModel.getUiDataModel().setSelectedTabIndex(position);
}
}
/**
- * Called by the LabelDialogFormat class after the dialog is finished.
+ * If this listener is attached to {@link #mHideAnimation} when it ends, the corresponding
+ * {@link #mShowAnimation} is automatically started.
*/
- @Override
- public void onDialogLabelSet(Alarm alarm, String label, String tag) {
- Fragment frag = getFragmentManager().findFragmentByTag(tag);
- if (frag instanceof AlarmClockFragment) {
- ((AlarmClockFragment) frag).setLabel(alarm, label);
+ private class AutoStartShowListener extends AnimatorListenerAdapter {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Prepare the hide animation for its next use; by default do not auto-show after hide.
+ mHideAnimation.removeListener(mAutoStartShowListener);
+
+ // Update the buttons now that they are no longer visible.
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
+
+ // Automatically start the grow animation now that shrinking is complete.
+ mShowAnimation.start();
+
+ // The animation to show the fab has begun; update the state to showing.
+ mFabState = FabState.SHOWING;
}
}
- public int getSelectedTab() {
- return mSelectedTab;
+ /**
+ * As the model reports changes to the selected tab, update the user interface.
+ */
+ private class TabChangeWatcher implements TabListener {
+ @Override
+ public void selectedTabChanged(Tab oldSelectedTab, Tab newSelectedTab) {
+ final int index = newSelectedTab.ordinal();
+
+ // Update the view pager and tab layout to agree with the model.
+ updateCurrentTab(index);
+
+ // Avoid sending events for the initial tab selection on launch and re-selecting a tab
+ // after a configuration change.
+ if (DataModel.getDataModel().isApplicationInForeground()) {
+ switch (newSelectedTab) {
+ case ALARMS:
+ Events.sendAlarmEvent(R.string.action_show, R.string.label_deskclock);
+ break;
+ case CLOCKS:
+ Events.sendClockEvent(R.string.action_show, R.string.label_deskclock);
+ break;
+ case TIMERS:
+ Events.sendTimerEvent(R.string.action_show, R.string.label_deskclock);
+ break;
+ case STOPWATCH:
+ Events.sendStopwatchEvent(R.string.action_show, R.string.label_deskclock);
+ break;
+ }
+ }
+
+ // If the hide animation has already completed, the buttons must be updated now when the
+ // new tab is known. Otherwise they are updated at the end of the hide animation.
+ if (!mHideAnimation.isStarted()) {
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
+ }
+ }
}
- public ImageView getFab() {
- return mFab;
- }
+ /**
+ * This adapter produces the DeskClockFragments that are the contents of the tabs.
+ */
+ private static class TabFragmentAdapter extends FragmentPagerAdapter {
- public ImageButton getLeftButton() {
- return mLeftButton;
- }
+ private final FragmentManager mFragmentManager;
+ private final Context mContext;
- public ImageButton getRightButton() {
- return mRightButton;
+ public TabFragmentAdapter(AppCompatActivity activity) {
+ super(activity.getFragmentManager());
+ mContext = activity;
+ mFragmentManager = activity.getFragmentManager();
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ position = UiDataModel.getUiDataModel().getTabLayoutIndex(position);
+ return super.instantiateItem(container, position);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ final String tag = makeFragmentName(R.id.desk_clock_pager, position);
+ Fragment fragment = mFragmentManager.findFragmentByTag(tag);
+ if (fragment == null) {
+ final Tab tab = UiDataModel.getUiDataModel().getTab(position);
+ final String fragmentClassName = tab.getFragmentClassName();
+ fragment = Fragment.instantiate(mContext, fragmentClassName);
+ }
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return UiDataModel.getUiDataModel().getTabCount();
+ }
+
+ /** This implementation duplicated from {@link FragmentPagerAdapter#makeFragmentName}. */
+ private String makeFragmentName(int viewId, long id) {
+ return "android:switcher:" + viewId + ":" + id;
+ }
}
}
diff --git a/src/com/android/deskclock/DeskClockApplication.java b/src/com/android/deskclock/DeskClockApplication.java
index c560f01..8edac6b 100644
--- a/src/com/android/deskclock/DeskClockApplication.java
+++ b/src/com/android/deskclock/DeskClockApplication.java
@@ -17,10 +17,12 @@
package com.android.deskclock;
import android.app.Application;
+import android.content.Context;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.events.Events;
import com.android.deskclock.events.LogEventTracker;
+import com.android.deskclock.uidata.UiDataModel;
public class DeskClockApplication extends Application {
@@ -28,8 +30,9 @@
public void onCreate() {
super.onCreate();
- DataModel.getDataModel().setContext(getApplicationContext());
-
- Events.addEventTracker(new LogEventTracker(getApplicationContext()));
+ final Context applicationContext = getApplicationContext();
+ DataModel.getDataModel().setContext(applicationContext);
+ UiDataModel.getUiDataModel().setContext(applicationContext);
+ Events.addEventTracker(new LogEventTracker(applicationContext));
}
}
diff --git a/src/com/android/deskclock/DeskClockFragment.java b/src/com/android/deskclock/DeskClockFragment.java
index 669f1ef..ff5bf68 100644
--- a/src/com/android/deskclock/DeskClockFragment.java
+++ b/src/com/android/deskclock/DeskClockFragment.java
@@ -16,61 +16,61 @@
package com.android.deskclock;
-import android.app.Activity;
import android.app.Fragment;
-import android.os.Bundle;
-import android.view.View;
+import android.support.annotation.NonNull;
import android.widget.ImageButton;
-import android.widget.ImageView;
-public class DeskClockFragment extends Fragment {
+import com.android.deskclock.uidata.UiDataModel;
+import com.android.deskclock.uidata.UiDataModel.Tab;
- protected ImageView mFab;
- protected ImageButton mLeftButton;
- protected ImageButton mRightButton;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_AND_BUTTONS_IMMEDIATE;
- public void onPageChanged(int page) {
- // Do nothing here , only in derived classes
- }
+public abstract class DeskClockFragment extends Fragment implements FabContainer, FabController {
- public void onFabClick(View view){
- // Do nothing here , only in derived classes
+ /** The tab associated with this fragment. */
+ private final Tab mTab;
+
+ public DeskClockFragment(Tab tab) {
+ mTab = tab;
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- final Activity activity = getActivity();
- if (activity instanceof DeskClock) {
- final DeskClock deskClockActivity = (DeskClock) activity;
- mFab = deskClockActivity.getFab();
- mLeftButton = deskClockActivity.getLeftButton();
- mRightButton = deskClockActivity.getRightButton();
+ public void onResume() {
+ super.onResume();
+
+ // Update the fab and buttons in case their state changed while the fragment was paused.
+ if (isTabSelected()) {
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
}
}
- public void setFabAppearance() {
- // Do nothing here , only in derived classes
+ @Override
+ public void onLeftButtonClick(@NonNull ImageButton left) {
+ // Do nothing here, only in derived classes
}
- public void setLeftRightButtonAppearance() {
- // Do nothing here , only in derived classes
+ @Override
+ public void onRightButtonClick(@NonNull ImageButton right) {
+ // Do nothing here, only in derived classes
}
- public void onLeftButtonClick(View view) {
- // Do nothing here , only in derived classes
+ /**
+ * Requests that the parent activity update the fab and buttons.
+ *
+ * @param updateType the manner in which the fab container should be updated
+ */
+ @Override
+ public final void updateFab(FabContainer.UpdateType updateType) {
+ final FabContainer parentFabContainer = (FabContainer) getActivity();
+ if (parentFabContainer != null) {
+ parentFabContainer.updateFab(updateType);
+ }
}
- public void onRightButtonClick(View view) {
- // Do nothing here , only in derived classes
+ /**
+ * @return {@code true} iff the currently selected tab displays this fragment
+ */
+ public final boolean isTabSelected() {
+ return UiDataModel.getUiDataModel().getSelectedTab() == mTab;
}
-
- protected final DeskClock getDeskClock() {
- return (DeskClock) getActivity();
- }
-
- protected final int getSelectedTab() {
- final DeskClock deskClock = getDeskClock();
- return deskClock == null ? -1 : deskClock.getSelectedTab();
- }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/FabContainer.java b/src/com/android/deskclock/FabContainer.java
new file mode 100644
index 0000000..6899743
--- /dev/null
+++ b/src/com/android/deskclock/FabContainer.java
@@ -0,0 +1,32 @@
+package com.android.deskclock;
+
+/**
+ * Implemented by containers that house the fab and its associated buttons. Also implemented by
+ * containers that know how to contact the <strong>true</strong> fab container to ferry through
+ * commands.
+ */
+public interface FabContainer {
+
+ enum UpdateType {
+ /** Signals just the fab should be "animated away", updated, and "animated back". */
+ FAB_ONLY_ANIMATED,
+
+ /** Signals the fab and buttons should be "animated away", updated, and "animated back". */
+ FAB_AND_BUTTONS_ANIMATED,
+
+ /** Signals that the fab and buttons should be updated in place with no animation. */
+ FAB_AND_BUTTONS_IMMEDIATE,
+
+ /** Disable the buttons of the fab so they do not respond to clicks. */
+ DISABLE_BUTTONS
+ }
+
+ /**
+ * Requests that this container update the fab and/or its buttons because their state has
+ * changed. The update may be immediate or it may be animated depending on the choice of
+ * {@code updateType}.
+ *
+ * @param updateType indicates the type of update to apply to the fab and its buttons
+ */
+ void updateFab(UpdateType updateType);
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/FabController.java b/src/com/android/deskclock/FabController.java
new file mode 100644
index 0000000..e507009
--- /dev/null
+++ b/src/com/android/deskclock/FabController.java
@@ -0,0 +1,53 @@
+package com.android.deskclock;
+
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+/**
+ * Implementers of this interface are able to {@link #onUpdateFab configure the fab} and associated
+ * {@link #onUpdateFabButtons left/right buttons} including setting them {@link View#INVISIBLE} if
+ * they are unnecessary. Implementers also attach click handler logic to the
+ * {@link #onFabClick fab}, {@link #onLeftButtonClick left button} and
+ * {@link #onRightButtonClick right button}.
+ */
+public interface FabController {
+
+ /**
+ * Configures the display of the fab component to match the current state of this controller.
+ *
+ * @param fab the fab component to be configured based on current state
+ */
+ void onUpdateFab(@NonNull ImageView fab);
+
+ /**
+ * Configures the display of the buttons to the left and right of the fab to match the current
+ * state of this controller.
+ *
+ * @param left button to the left of the fab to configure based on current state
+ * @param right button to the right of the fab to configure based on current state
+ */
+ void onUpdateFabButtons(@NonNull ImageButton left, @NonNull ImageButton right);
+
+ /**
+ * Handles a click on the fab.
+ *
+ * @param fab the fab component on which the click occurred
+ */
+ void onFabClick(@NonNull ImageView fab);
+
+ /**
+ * Handles a click on the button to the left of the fab component.
+ *
+ * @param left the button to the left of the fab component
+ */
+ void onLeftButtonClick(@NonNull ImageButton left);
+
+ /**
+ * Handles a click on the button to the right of the fab component.
+ *
+ * @param right the button to the right of the fab component
+ */
+ void onRightButtonClick(@NonNull ImageButton right);
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/HandleApiCalls.java b/src/com/android/deskclock/HandleApiCalls.java
index 06cb65a..8212c7f 100644
--- a/src/com/android/deskclock/HandleApiCalls.java
+++ b/src/com/android/deskclock/HandleApiCalls.java
@@ -38,6 +38,7 @@
import com.android.deskclock.provider.AlarmInstance;
import com.android.deskclock.provider.DaysOfWeek;
import com.android.deskclock.timer.TimerFragment;
+import com.android.deskclock.uidata.UiDataModel;
import java.util.ArrayList;
import java.util.Calendar;
@@ -45,6 +46,8 @@
import java.util.List;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.deskclock.uidata.UiDataModel.Tab.ALARMS;
+import static com.android.deskclock.uidata.UiDataModel.Tab.TIMERS;
/**
* This activity is never visible. It processes all public intents defined by {@link AlarmClock}
@@ -76,7 +79,7 @@
handleSetTimer(intent);
break;
case AlarmClock.ACTION_DISMISS_ALARM:
- handleDismissAlarm(intent.getAction());
+ handleDismissAlarm(intent);
break;
case AlarmClock.ACTION_SNOOZE_ALARM:
handleSnoozeAlarm();
@@ -86,15 +89,12 @@
}
}
- private void handleDismissAlarm(final String action) {
- // Opens the UI for Alarms
- final Intent alarmIntent =
- Alarm.createIntent(mAppContext, DeskClock.class, Alarm.INVALID_ID)
- .setAction(action)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
- startActivity(alarmIntent);
+ private void handleDismissAlarm(Intent intent) {
+ // Change to the alarms tab.
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
- final Intent intent = getIntent();
+ // Open DeskClock which is now positioned on the alarms tab.
+ startActivity(new Intent(mAppContext, DeskClock.class));
new DismissAlarmAsync(mAppContext, intent, this).execute();
}
@@ -273,11 +273,15 @@
minutes = 0;
}
if (hour < 0 || hour > 23 || minutes < 0 || minutes > 59) {
- // Intent has no time or an invalid time, open the alarm creation UI
- Intent createAlarm = Alarm.createIntent(this, DeskClock.class, Alarm.INVALID_ID);
- createAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- createAlarm.putExtra(AlarmClockFragment.ALARM_CREATE_NEW_INTENT_EXTRA, true);
- createAlarm.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
+ // Change to the alarms tab.
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
+
+ // Intent has no time or an invalid time, open the alarm creation UI.
+ final Intent createAlarm = Alarm.createIntent(this, DeskClock.class, Alarm.INVALID_ID)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .putExtra(AlarmClockFragment.ALARM_CREATE_NEW_INTENT_EXTRA, true);
+
+ // Open DeskClock which is now positioned on the alarms tab.
startActivity(createAlarm);
Voice.notifyFailure(this, getString(R.string.invalid_time, hour, minutes, " "));
LogUtils.i("HandleApiCalls no/invalid time; opening UI");
@@ -322,8 +326,12 @@
}
private void handleShowAlarms() {
- startActivity(new Intent(this, DeskClock.class)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX));
+ // Change to the alarms tab.
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
+
+ // Open DeskClock which is now positioned on the alarms tab.
+ startActivity(new Intent(this, DeskClock.class));
+
Events.sendAlarmEvent(R.string.action_show, R.string.label_intent);
LogUtils.i("HandleApiCalls show alarms");
}
@@ -331,6 +339,10 @@
private void handleSetTimer(Intent intent) {
// If no length is supplied, show the timer setup view.
if (!intent.hasExtra(AlarmClock.EXTRA_LENGTH)) {
+ // Change to the timers tab.
+ UiDataModel.getUiDataModel().setSelectedTab(TIMERS);
+
+ // Open DeskClock which is now positioned on the timers tab and show the timer setup.
startActivity(TimerFragment.createTimerSetupIntent(this));
LogUtils.i("HandleApiCalls showing timer setup");
return;
@@ -371,8 +383,11 @@
// If not instructed to skip the UI, display the running timer.
if (!skipUi) {
+ // Change to the timers tab.
+ UiDataModel.getUiDataModel().setSelectedTab(TIMERS);
+
+ // Open DeskClock which is now positioned on the timers tab.
startActivity(new Intent(this, DeskClock.class)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX)
.putExtra(HandleDeskClockApiCalls.EXTRA_TIMER_ID, timer.getId()));
}
}
@@ -382,10 +397,13 @@
AlarmStateManager.registerInstance(this, instance, true);
AlarmUtils.popAlarmSetToast(this, instance.getAlarmTime().getTimeInMillis());
if (!skipUi) {
- Intent showAlarm = Alarm.createIntent(this, DeskClock.class, instance.mAlarmId);
- showAlarm.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
- showAlarm.putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, instance.mAlarmId);
- showAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Change to the alarms tab.
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
+
+ // Open DeskClock which is now positioned on the alarms tab.
+ final Intent showAlarm = Alarm.createIntent(this, DeskClock.class, instance.mAlarmId)
+ .putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, instance.mAlarmId)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(showAlarm);
}
}
diff --git a/src/com/android/deskclock/HandleDeskClockApiCalls.java b/src/com/android/deskclock/HandleDeskClockApiCalls.java
index 224bf19..ee3f433 100644
--- a/src/com/android/deskclock/HandleDeskClockApiCalls.java
+++ b/src/com/android/deskclock/HandleDeskClockApiCalls.java
@@ -25,13 +25,17 @@
import com.android.deskclock.data.DataModel;
import com.android.deskclock.data.Timer;
import com.android.deskclock.events.Events;
+import com.android.deskclock.uidata.UiDataModel;
import com.android.deskclock.worldclock.CitySelectionActivity;
import java.util.List;
import java.util.Set;
+import static com.android.deskclock.uidata.UiDataModel.Tab.CLOCKS;
+import static com.android.deskclock.uidata.UiDataModel.Tab.STOPWATCH;
+import static com.android.deskclock.uidata.UiDataModel.Tab.TIMERS;
+
public class HandleDeskClockApiCalls extends Activity {
- private Context mAppContext;
private static final String ACTION_PREFIX = "com.android.deskclock.action.";
@@ -70,12 +74,13 @@
public static final String ACTION_ADD_MINUTE_TIMER = ACTION_PREFIX + "ADD_MINUTE_TIMER";
// extra for many actions specific to a given timer
- public static final String EXTRA_TIMER_ID =
- "com.android.deskclock.extra.TIMER_ID";
+ public static final String EXTRA_TIMER_ID = "com.android.deskclock.extra.TIMER_ID";
// Describes the entity responsible for the action being performed.
public static final String EXTRA_EVENT_LABEL = "com.android.deskclock.extra.EVENT_LABEL";
+ private Context mAppContext;
+
@Override
protected void onCreate(Bundle icicle) {
try {
@@ -169,10 +174,11 @@
LogUtils.i(reason);
}
- // Open the UI to the stopwatch.
- final Intent stopwatchIntent = new Intent(mAppContext, DeskClock.class)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.STOPWATCH_TAB_INDEX);
- startActivity(stopwatchIntent);
+ // Change to the stopwatch tab.
+ UiDataModel.getUiDataModel().setSelectedTab(STOPWATCH);
+
+ // Open DeskClock which is now positioned on the stopwatch tab.
+ startActivity(new Intent(mAppContext, DeskClock.class));
}
private void handleTimerIntent(Intent intent) {
@@ -215,8 +221,8 @@
// Otherwise the control command can be honored.
switch (action) {
case ACTION_RESET_TIMER: {
- DataModel.getDataModel().resetOrDeleteTimer(timer, eventLabel);
- if (timer.isExpired() && timer.getDeleteAfterUse()) {
+ timer = DataModel.getDataModel().resetOrDeleteTimer(timer, eventLabel);
+ if (timer == null) {
timerId = -1;
reason = getString(R.string.timer_deleted);
} else {
@@ -246,9 +252,11 @@
LogUtils.i(reason);
}
- // Open the UI to the timers.
- final Intent showTimers = new Intent(mAppContext, DeskClock.class)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX);
+ // Change to the timers tab.
+ UiDataModel.getUiDataModel().setSelectedTab(TIMERS);
+
+ // Open DeskClock which is now positioned on the timers tab and show the timer in question.
+ final Intent showTimers = new Intent(mAppContext, DeskClock.class);
if (timerId != -1) {
showTimers.putExtra(EXTRA_TIMER_ID, timerId);
}
@@ -263,6 +271,15 @@
final int label = fromWidget ? R.string.label_widget : R.string.label_intent;
Events.sendClockEvent(R.string.action_show, label);
} else {
+ switch (action) {
+ case ACTION_ADD_CLOCK:
+ Events.sendClockEvent(R.string.action_add, R.string.label_intent);
+ break;
+ case ACTION_DELETE_CLOCK:
+ Events.sendClockEvent(R.string.action_delete, R.string.label_intent);
+ break;
+ }
+
final String cityName = intent.getStringExtra(EXTRA_CITY);
final String reason;
@@ -275,14 +292,6 @@
Voice.notifySuccess(this, reason);
startActivity(new Intent(this, CitySelectionActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
- switch (action) {
- case ACTION_ADD_CLOCK:
- Events.sendClockEvent(R.string.action_add, R.string.label_intent);
- break;
- case ACTION_DELETE_CLOCK:
- Events.sendClockEvent(R.string.action_delete, R.string.label_intent);
- break;
- }
return;
}
@@ -292,14 +301,8 @@
reason = getString(R.string.the_city_you_specified_is_not_available);
LogUtils.i(reason);
Voice.notifyFailure(this, reason);
- switch (action) {
- case ACTION_ADD_CLOCK:
- Events.sendClockEvent(R.string.action_add, R.string.label_intent);
- break;
- case ACTION_DELETE_CLOCK:
- Events.sendClockEvent(R.string.action_delete, R.string.label_intent);
- break;
- }
+ startActivity(new Intent(this, CitySelectionActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
return;
}
@@ -318,7 +321,6 @@
// Otherwise report the success.
DataModel.getDataModel().setSelectedCities(selectedCities);
reason = getString(R.string.city_added, city.getName());
- Events.sendClockEvent(R.string.action_add, R.string.label_intent);
break;
}
case ACTION_DELETE_CLOCK: {
@@ -332,7 +334,6 @@
// Otherwise report the success.
DataModel.getDataModel().setSelectedCities(selectedCities);
reason = getString(R.string.city_deleted, city.getName());
- Events.sendClockEvent(R.string.action_delete, R.string.label_intent);
break;
}
default:
@@ -347,11 +348,10 @@
LogUtils.i(reason);
}
- // Opens the UI for clocks
- final Intent clockIntent = new Intent(mAppContext, DeskClock.class)
- .setAction(action)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.CLOCK_TAB_INDEX);
- startActivity(clockIntent);
+ // Change to the clocks tab.
+ UiDataModel.getUiDataModel().setSelectedTab(CLOCKS);
+
+ // Open DeskClock which is now positioned on the clocks tab.
+ startActivity(new Intent(mAppContext, DeskClock.class));
}
}
\ No newline at end of file
diff --git a/src/com/android/deskclock/ItemAdapter.java b/src/com/android/deskclock/ItemAdapter.java
new file mode 100644
index 0000000..f67abce
--- /dev/null
+++ b/src/com/android/deskclock/ItemAdapter.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock;
+
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base adapter class for displaying a collection of items. Provides functionality for handling
+ * changing items, persistent item state, item click events, and re-usable item views.
+ */
+public class ItemAdapter<T extends ItemAdapter.ItemHolder> extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> {
+
+ /**
+ * Finds the position of the changed item holder and invokes {@link #notifyItemChanged(int)}.
+ */
+ private final OnItemChangedListener mItemChangedNotifier = new OnItemChangedListener() {
+ @Override
+ public void onItemChanged(ItemHolder<?> itemHolder) {
+ if (mOnItemChangedListener != null) {
+ mOnItemChangedListener.onItemChanged(itemHolder);
+ }
+ final int position = mItemHolders.indexOf(itemHolder);
+ if (position != RecyclerView.NO_POSITION) {
+ notifyItemChanged(position);
+ }
+ }
+ };
+
+ /**
+ * Invokes the {@link OnItemClickedListener} in {@link #mListenersByViewType} corresponding
+ * to {@link ItemViewHolder#getItemViewType()}
+ */
+ private final OnItemClickedListener mOnItemClickedListener = new OnItemClickedListener() {
+ @Override
+ public void onItemClicked(ItemViewHolder<?> viewHolder, int id) {
+ final OnItemClickedListener listener =
+ mListenersByViewType.get(viewHolder.getItemViewType());
+ if (listener != null) {
+ listener.onItemClicked(viewHolder, id);
+ }
+ }
+ };
+
+ /**
+ * Invoked when any item changes.
+ */
+ private OnItemChangedListener mOnItemChangedListener;
+
+ /**
+ * Factories for creating new {@link ItemViewHolder} entities.
+ */
+ private final SparseArray<ItemViewHolder.Factory> mFactoriesByViewType = new SparseArray<>();
+
+ /**
+ * Listeners to invoke in {@link #mOnItemClickedListener}.
+ */
+ private final SparseArray<OnItemClickedListener> mListenersByViewType = new SparseArray<>();
+
+ /**
+ * List of current item holders represented by this adapter.
+ */
+ private List<T> mItemHolders;
+
+ /**
+ * Convenience for calling {@link #setHasStableIds(boolean)} with {@code true}.
+ *
+ * @return this object, allowing calls to methods in this class to be chained
+ */
+ public ItemAdapter setHasStableIds() {
+ setHasStableIds(true);
+ return this;
+ }
+
+ /**
+ * Sets the {@link ItemViewHolder.Factory} and {@link OnItemClickedListener} used to create
+ * new item view holders in {@link #onCreateViewHolder(ViewGroup, int)}.
+ *
+ * @param factory the {@link ItemViewHolder.Factory} used to create new item view holders
+ * @param listener the {@link OnItemClickedListener} to be invoked by
+ * {@link #mItemChangedNotifier}
+ * @param viewTypes the unique identifier for the view types to be created
+ * @return this object, allowing calls to methods in this class to be chained
+ */
+ public ItemAdapter withViewTypes(ItemViewHolder.Factory factory,
+ OnItemClickedListener listener, int... viewTypes) {
+ for (int viewType : viewTypes) {
+ mFactoriesByViewType.put(viewType, factory);
+ mListenersByViewType.put(viewType, listener);
+ }
+ return this;
+ }
+
+ /**
+ * @return the current list of item holders represented by this adapter
+ */
+ public final List<T> getItems() {
+ return mItemHolders;
+ }
+
+ /**
+ * Sets the list of item holders to serve as the dataset for this adapter and invokes
+ * {@link #notifyDataSetChanged()} to update the UI.
+ * <p/>
+ * If {@link #hasStableIds()} returns {@code true}, then the instance state will preserved
+ * between new and old holders that have matching {@link ItemHolder#itemId} values.
+ *
+ * @param itemHolders the new list of item holders
+ * @return this object, allowing calls to methods in this class to be chained
+ */
+ public ItemAdapter setItems(List<T> itemHolders) {
+ final List<T> oldItemHolders = mItemHolders;
+ if (oldItemHolders != itemHolders) {
+ if (oldItemHolders != null) {
+ // remove the item change listener from the old item holders
+ for (T oldItemHolder : oldItemHolders) {
+ oldItemHolder.removeOnItemChangedListener(mItemChangedNotifier);
+ }
+ }
+
+ if (oldItemHolders != null && itemHolders != null && hasStableIds()) {
+ // transfer instance state from old to new item holders based on item id,
+ // we use a simple O(N^2) implementation since we assume the number of items is
+ // relatively small and generating a temporary map would be more expensive
+ final Bundle bundle = new Bundle();
+ for (ItemHolder newItemHolder : itemHolders) {
+ for (ItemHolder oldItemHolder : oldItemHolders) {
+ if (newItemHolder.itemId == oldItemHolder.itemId
+ && newItemHolder != oldItemHolder) {
+ // clear any existing state from the bundle
+ bundle.clear();
+
+ // transfer instance state from old to new item holder
+ oldItemHolder.onSaveInstanceState(bundle);
+ newItemHolder.onRestoreInstanceState(bundle);
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (itemHolders != null) {
+ // add the item change listener to the new item holders
+ for (ItemHolder newItemHolder : itemHolders) {
+ newItemHolder.addOnItemChangedListener(mItemChangedNotifier);
+ }
+ }
+
+ // finally update the current list of item holders and inform the RV to update the UI
+ mItemHolders = itemHolders;
+ notifyDataSetChanged();
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the listener to be invoked whenever any item changes.
+ */
+ public void setOnItemChangedListener(OnItemChangedListener listener) {
+ mOnItemChangedListener = listener;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItemHolders == null ? 0 : mItemHolders.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mItemHolders.get(position).itemId;
+ }
+
+ public T findItemById(long id) {
+ for (T holder : mItemHolders) {
+ if (holder.itemId == id) {
+ return holder;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mItemHolders.get(position).getItemViewType();
+ }
+
+ @Override
+ public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final ItemViewHolder.Factory factory = mFactoriesByViewType.get(viewType);
+ if (factory != null) {
+ return factory.createViewHolder(parent, viewType);
+ }
+ throw new IllegalArgumentException("Unsupported view type: " + viewType);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void onBindViewHolder(ItemViewHolder viewHolder, int position) {
+ // suppress any unchecked warnings since it is up to the subclass to guarantee
+ // compatibility of their view holders with the item holder at the corresponding position
+ viewHolder.bindItemView(mItemHolders.get(position));
+ viewHolder.setOnItemClickedListener(mOnItemClickedListener);
+ }
+
+ @Override
+ public void onViewRecycled(ItemViewHolder viewHolder) {
+ viewHolder.setOnItemClickedListener(null);
+ viewHolder.recycleItemView();
+ }
+
+ /**
+ * Base class for wrapping an item for compatibility with an {@link ItemHolder}.
+ * <p/>
+ * An {@link ItemHolder} serves as bridge between the model and view layer; subclassers should
+ * implement properties that fall beyond the scope of their model layer but are necessary for
+ * the view layer. Properties that should be persisted across dataset changes can be
+ * preserved via the {@link #onSaveInstanceState(Bundle)} and
+ * {@link #onRestoreInstanceState(Bundle)} methods.
+ * <p/>
+ * Note: An {@link ItemHolder} can be used by multiple {@link ItemHolder} and any state changes
+ * should simultaneously be reflected in both UIs. It is not thread-safe however and should
+ * only be used on a single thread at a given time.
+ *
+ * @param <T> the item type wrapped by the holder
+ */
+ public static abstract class ItemHolder<T> {
+
+ /**
+ * The item held by this holder.
+ */
+ public final T item;
+
+ /**
+ * Globally unique id corresponding to the item.
+ */
+ public final long itemId;
+
+ /**
+ * Listeners to be invoked by {@link #notifyItemChanged()}.
+ */
+ private final List<OnItemChangedListener> mOnItemChangedListeners = new ArrayList<>();
+
+ /**
+ * Designated constructor.
+ *
+ * @param item the {@link T} item to be held by this holder
+ * @param itemId the globally unique id corresponding to the item
+ */
+ public ItemHolder(T item, long itemId) {
+ this.item = item;
+ this.itemId = itemId;
+ }
+
+ /**
+ * @return the unique identifier for the view that should be used to represent the item,
+ * e.g. the layout resource id.
+ */
+ public abstract int getItemViewType();
+
+ /**
+ * Adds the listener to the current list of registered listeners if it is not already
+ * registered.
+ *
+ * @param listener the listener to add
+ */
+ public final void addOnItemChangedListener(OnItemChangedListener listener) {
+ if (!mOnItemChangedListeners.contains(listener)) {
+ mOnItemChangedListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes the listener from the current list of registered listeners.
+ *
+ * @param listener the listener to remove
+ */
+ public final void removeOnItemChangedListener(OnItemChangedListener listener) {
+ mOnItemChangedListeners.remove(listener);
+ }
+
+ /**
+ * Invokes {@link OnItemChangedListener#onItemChanged(ItemHolder)} for all listeners added
+ * via {@link #addOnItemChangedListener(OnItemChangedListener)}.
+ */
+ public final void notifyItemChanged() {
+ for (OnItemChangedListener listener : mOnItemChangedListeners) {
+ listener.onItemChanged(this);
+ }
+ }
+
+ /**
+ * Called to retrieve per-instance state when the item may disappear or change so that
+ * state can be restored in {@link #onRestoreInstanceState(Bundle)}.
+ * <p/>
+ * Note: Subclasses must not maintain a reference to the {@link Bundle} as it may be
+ * reused for other items in the {@link ItemHolder}.
+ *
+ * @param bundle the {@link Bundle} in which to place saved state
+ */
+ public void onSaveInstanceState(Bundle bundle) {
+ // for subclassers
+ }
+
+ /**
+ * Called to restore any per-instance state which was previously saved in
+ * {@link #onSaveInstanceState(Bundle)} for an item with a matching {@link #itemId}.
+ * <p/>
+ * Note: Subclasses must not maintain a reference to the {@link Bundle} as it may be
+ * reused for other items in the {@link ItemHolder}.
+ *
+ * @param bundle the {@link Bundle} in which to retrieve saved state
+ */
+ public void onRestoreInstanceState(Bundle bundle) {
+ // for subclassers
+ }
+ }
+
+ /**
+ * Base class for a reusable {@link RecyclerView.ViewHolder} compatible with an
+ * {@link ItemViewHolder}. Provides an interface for binding to an {@link ItemHolder} and later
+ * being recycled.
+ */
+ public static class ItemViewHolder<T extends ItemHolder> extends RecyclerView.ViewHolder {
+
+ /**
+ * The current {@link ItemHolder} bound to this holder.
+ */
+ private T mItemHolder;
+
+ /**
+ * The current {@link OnItemClickedListener} associated with this holder.
+ */
+ private OnItemClickedListener mOnItemClickedListener;
+
+ /**
+ * Designated constructor.
+ *
+ * @param itemView the item {@link View} to associate with this holder
+ */
+ public ItemViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ /**
+ * @return the current {@link ItemHolder} bound to this holder, or {@code null} if unbound
+ */
+ public final T getItemHolder() {
+ return mItemHolder;
+ }
+
+ /**
+ * Binds the holder's {@link #itemView} to a particular item.
+ *
+ * @param itemHolder the {@link ItemHolder} to bind
+ */
+ public final void bindItemView(T itemHolder) {
+ mItemHolder = itemHolder;
+ onBindItemView(itemHolder);
+ }
+
+ /**
+ * Called when a new item is bound to the holder. Subclassers should override to bind any
+ * relevant data to their {@link #itemView} in this method.
+ *
+ * @param itemHolder the {@link ItemHolder} to bind
+ */
+ protected void onBindItemView(T itemHolder) {
+ // for subclassers
+ }
+
+ /**
+ * Recycles the current item view, unbinding the current item holder and state.
+ */
+ public final void recycleItemView() {
+ mItemHolder = null;
+ mOnItemClickedListener = null;
+
+ onRecycleItemView();
+ }
+
+ /**
+ * Called when the current item view is recycled. Subclassers should override to release
+ * any bound item state and prepare their {@link #itemView} for reuse.
+ */
+ protected void onRecycleItemView() {
+ // for subclassers
+ }
+
+ /**
+ * Sets the current {@link OnItemClickedListener} to be invoked via
+ * {@link #notifyItemClicked}.
+ *
+ * @param listener the new {@link OnItemClickedListener}, or {@code null} to clear
+ */
+ public final void setOnItemClickedListener(OnItemClickedListener listener) {
+ mOnItemClickedListener = listener;
+ }
+
+ /**
+ * Called by subclasses to invoke the current {@link OnItemClickedListener} for a
+ * particular click event so it can be handled at a higher level.
+ *
+ * @param id the unique identifier for the click action that has occurred
+ */
+ public final void notifyItemClicked(int id) {
+ if (mOnItemClickedListener != null) {
+ mOnItemClickedListener.onItemClicked(this, id);
+ }
+ }
+
+ /**
+ * Factory interface used by {@link ItemAdapter} for creating new {@link ItemViewHolder}.
+ */
+ public interface Factory {
+ /**
+ * Used by {@link ItemAdapter#createViewHolder(ViewGroup, int)} to make new
+ * {@link ItemViewHolder} for a given view type.
+ *
+ * @param parent the {@code ViewGroup} that the {@link ItemViewHolder#itemView} will
+ * be attached
+ * @param viewType the unique id of the item view to create
+ * @return a new initialized {@link ItemViewHolder}
+ */
+ public ItemViewHolder<?> createViewHolder(ViewGroup parent, int viewType);
+ }
+ }
+
+ /**
+ * Callback interface for when an item changes and should be re-bound.
+ */
+ public interface OnItemChangedListener {
+ /**
+ * Invoked by {@link ItemHolder#notifyItemChanged()}.
+ *
+ * @param itemHolder the item holder that has changed
+ */
+ public void onItemChanged(ItemHolder<?> itemHolder);
+ }
+
+ /**
+ * Callback interface for handling when an item is clicked.
+ */
+ public interface OnItemClickedListener {
+ /**
+ * Invoked by {@link ItemViewHolder#notifyItemClicked(int)}
+ *
+ * @param viewHolder the {@link ItemViewHolder} containing the view that was clicked
+ * @param id the unique identifier for the click action that has occurred
+ */
+ public void onItemClicked(ItemViewHolder<?> viewHolder, int id);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/NumberPickerCompat.java b/src/com/android/deskclock/NumberPickerCompat.java
index 89baed6..2fb5bed 100644
--- a/src/com/android/deskclock/NumberPickerCompat.java
+++ b/src/com/android/deskclock/NumberPickerCompat.java
@@ -134,6 +134,12 @@
postDelayed(mAnnounceValueRunnable, 200L);
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ removeCallbacks(mAnnounceValueRunnable);
+ }
+
/**
* Register a callback to be invoked whenever a value change should be announced.
*/
diff --git a/src/com/android/deskclock/RingtonePickerDialogFragment.java b/src/com/android/deskclock/RingtonePickerDialogFragment.java
new file mode 100644
index 0000000..69b4efe
--- /dev/null
+++ b/src/com/android/deskclock/RingtonePickerDialogFragment.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.Cursor;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AlertDialog;
+
+import com.android.deskclock.data.DataModel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This ringtone picker offers some flexibility over the system ringtone picker. It can be themed,
+ * and it allows control of the ringtones that are displayed and their labels.
+ */
+public class RingtonePickerDialogFragment extends DialogFragment {
+
+ private static final String KEY_TITLE = "title";
+ private static final String KEY_OLD_RINGTONE_URI = "old_ringtone_uri";
+ private static final String KEY_DEFAULT_RINGTONE_LABEL = "default_ringtone_label";
+ private static final String KEY_DEFAULT_RINGTONE_URI = "default_ringtone_uri";
+ private static final String KEY_FRAGMENT_TAG = "fragment_tag";
+ private static final String KEY_SELECTED_INDEX = "selected_index";
+
+ private int mSelectedIndex;
+
+ public static DialogFragment newInstance(String title, String
+ defaultRingtoneLabel, Uri defaultRingtoneUri, Uri oldRingtoneUri, String fragmentTag) {
+
+ final Bundle args = new Bundle();
+ args.putString(KEY_TITLE, title);
+ args.putString(KEY_DEFAULT_RINGTONE_LABEL, defaultRingtoneLabel);
+ args.putParcelable(KEY_DEFAULT_RINGTONE_URI, defaultRingtoneUri);
+ args.putParcelable(KEY_OLD_RINGTONE_URI, oldRingtoneUri);
+ args.putString(KEY_FRAGMENT_TAG, fragmentTag);
+ args.putInt(KEY_SELECTED_INDEX, -1);
+
+ final RingtonePickerDialogFragment fragment = new RingtonePickerDialogFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Bundle bundle = getArguments();
+ final String title = bundle.getString(KEY_TITLE);
+ final String defaultRingtoneLabel = bundle.getString(KEY_DEFAULT_RINGTONE_LABEL);
+ final Uri defaultRingtoneUri = bundle.getParcelable(KEY_DEFAULT_RINGTONE_URI);
+ final Uri oldRingtoneUri = bundle.getParcelable(KEY_OLD_RINGTONE_URI);
+ final String fragmentTag = bundle.getString(KEY_FRAGMENT_TAG);
+ mSelectedIndex = bundle.getInt(KEY_SELECTED_INDEX);
+ final List<RingtoneItem> ringtones = new ArrayList<>(20);
+
+ // Add option for "silent" ringtone.
+ final String silentTitle = getString(R.string.silent_ringtone_title);
+ final Uri silentUri = DataModel.getDataModel().getSilentRingtoneUri();
+ ringtones.add(new RingtoneItem(silentTitle, silentUri));
+
+ // Add option for default ringtone.
+ if (defaultRingtoneLabel != null) {
+ ringtones.add(new RingtoneItem(defaultRingtoneLabel, defaultRingtoneUri));
+ }
+
+ // Add system ringtones.
+ final Context context = getActivity();
+ final RingtoneManager rm = new RingtoneManager(context);
+ rm.setType(RingtoneManager.TYPE_ALARM);
+ final Cursor cursor = rm.getCursor();
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ final String ringtoneTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
+ final Uri ringtoneUri = rm.getRingtoneUri(cursor.getPosition());
+ ringtones.add(new RingtoneItem(ringtoneTitle, ringtoneUri));
+ }
+
+ // Extract the ringtone titles for the dialog to display.
+ final CharSequence[] titles = new CharSequence[ringtones.size()];
+ for (int i = 0; i < ringtones.size(); i++) {
+ final RingtoneItem ringtone = ringtones.get(i);
+ titles[i] = ringtone.title;
+ if (mSelectedIndex < 0 && ringtone.uri.equals(oldRingtoneUri)) {
+ mSelectedIndex = i;
+ }
+ }
+
+ return new AlertDialog.Builder(context)
+ .setTitle(title)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Uri uri = ringtones.get(mSelectedIndex).uri;
+ RingtoneSelectionListener rsl = (RingtoneSelectionListener) getActivity();
+ rsl.onRingtoneSelected(uri, fragmentTag);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .setSingleChoiceItems(titles, mSelectedIndex,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ selectRingtone(which, ringtones.get(which).uri);
+ }
+ })
+ .create();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (!getActivity().isChangingConfigurations()) {
+ RingtonePreviewKlaxon.stop(getActivity());
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(KEY_SELECTED_INDEX, mSelectedIndex);
+ }
+
+ /**
+ * Callback for ringtone click.
+ */
+ private void selectRingtone(int index, Uri ringtoneUri) {
+ mSelectedIndex = index;
+ final Context context = getActivity();
+ RingtonePreviewKlaxon.stop(context);
+
+ if (!DataModel.getDataModel().getSilentRingtoneUri().equals(ringtoneUri)) {
+ RingtonePreviewKlaxon.start(context, ringtoneUri);
+ }
+ }
+
+ private static class RingtoneItem {
+ public final String title;
+ public final Uri uri;
+
+ public RingtoneItem(String title, Uri uri) {
+ this.title = title;
+ this.uri = uri;
+ }
+ }
+
+ public interface RingtoneSelectionListener {
+ /**
+ * Called when the ringtone picker dialog is confirmed and dismissed.
+ *
+ * @param ringtoneUri the uri of the ringtone that was picked
+ * @param fragmentTag the tag of the fragment that launched the dialog
+ */
+ void onRingtoneSelected(Uri ringtoneUri, String fragmentTag);
+ }
+}
diff --git a/src/com/android/deskclock/RingtonePreviewKlaxon.java b/src/com/android/deskclock/RingtonePreviewKlaxon.java
new file mode 100644
index 0000000..d11ed7e
--- /dev/null
+++ b/src/com/android/deskclock/RingtonePreviewKlaxon.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock;
+
+import android.content.Context;
+import android.net.Uri;
+
+public final class RingtonePreviewKlaxon {
+
+ private static AsyncRingtonePlayer sAsyncRingtonePlayer;
+
+ private RingtonePreviewKlaxon() {
+ }
+
+ public static void stop(Context context) {
+ LogUtils.i("RingtonePreviewKlaxon.stop()");
+ getAsyncRingtonePlayer(context).stop();
+ }
+
+ public static void start(Context context, Uri uri) {
+ stop(context);
+ LogUtils.i("RingtonePreviewKlaxon.start()");
+ getAsyncRingtonePlayer(context).play(uri);
+ }
+
+ private static synchronized AsyncRingtonePlayer getAsyncRingtonePlayer(Context context) {
+ if (sAsyncRingtonePlayer == null) {
+ sAsyncRingtonePlayer = new AsyncRingtonePlayer(context.getApplicationContext(), null);
+ }
+
+ return sAsyncRingtonePlayer;
+ }
+}
diff --git a/src/com/android/deskclock/Screensaver.java b/src/com/android/deskclock/Screensaver.java
index 7ab6d92..a2197ce 100644
--- a/src/com/android/deskclock/Screensaver.java
+++ b/src/com/android/deskclock/Screensaver.java
@@ -23,6 +23,7 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
@@ -142,10 +143,9 @@
Utils.setMidnightUpdater(mHandler, mMidnightUpdater);
if (Utils.isPreL()) {
- getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED),
- false,
- mSettingsContentObserver);
+ @SuppressWarnings("deprecation")
+ final Uri uri = Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED);
+ getContentResolver().registerContentObserver(uri, false, mSettingsContentObserver);
}
mHandler.post(mMoveSaverRunnable);
diff --git a/src/com/android/deskclock/ScreensaverActivity.java b/src/com/android/deskclock/ScreensaverActivity.java
index 2754114..6d68664 100644
--- a/src/com/android/deskclock/ScreensaverActivity.java
+++ b/src/com/android/deskclock/ScreensaverActivity.java
@@ -23,6 +23,7 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.Handler;
import android.provider.Settings;
@@ -116,10 +117,9 @@
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(mIntentReceiver, filter);
if (Utils.isPreL()) {
- getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED),
- false,
- mSettingsContentObserver);
+ @SuppressWarnings("deprecation")
+ final Uri uri = Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED);
+ getContentResolver().registerContentObserver(uri, false, mSettingsContentObserver);
}
}
@@ -212,4 +212,4 @@
Utils.updateDate(mDateFormat, mDateFormatForAccessibility,mContentView);
Utils.refreshAlarm(ScreensaverActivity.this, mContentView);
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/Utils.java b/src/com/android/deskclock/Utils.java
index 49f3b81..16879c0 100644
--- a/src/com/android/deskclock/Utils.java
+++ b/src/com/android/deskclock/Utils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.content.ContentResolver;
@@ -36,12 +36,12 @@
import android.os.Looper;
import android.preference.PreferenceManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
-import android.text.format.Time;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
@@ -78,6 +78,8 @@
public static final int DEFAULT_WEEK_START = Calendar.getInstance().getFirstDayOfWeek();
+ private static final long QUARTER_HOUR_IN_MILLIS = 15 * DateUtils.MINUTE_IN_MILLIS;
+
private static Locale sLocaleUsedForWeekdays;
/**
@@ -136,7 +138,7 @@
/**
* @return {@code true} if the device is {@link Build.VERSION_CODES#LOLLIPOP} or
- * {@link Build.VERSION_CODES#LOLLIPOP_MR1}
+ * {@link Build.VERSION_CODES#LOLLIPOP_MR1}
*/
public static boolean isLOrLMR1() {
final int sdkInt = Build.VERSION.SDK_INT;
@@ -188,30 +190,20 @@
}
}
- /** Runnable for use with screensaver and dream, to move the clock every minute.
- * registerViews() must be called prior to posting.
+ /**
+ * Runnable for use with screensaver and dream, to move the clock every minute.
+ * registerViews() must be called prior to posting.
*/
public static class ScreensaverMoveSaverRunnable implements Runnable {
- static final long MOVE_DELAY = 60000; // DeskClock.SCREEN_SAVER_MOVE_DELAY;
- static final long SLIDE_TIME = 10000;
- static final long FADE_TIME = 3000;
- static final boolean SLIDE = false;
+ static final long MOVE_DELAY = 60000; // DeskClock.SCREEN_SAVER_MOVE_DELAY;
+ static final long FADE_TIME = 3000;
private View mContentView, mSaverView;
private final Handler mHandler;
- private static TimeInterpolator mSlowStartWithBrakes;
-
-
public ScreensaverMoveSaverRunnable(Handler handler) {
mHandler = handler;
- mSlowStartWithBrakes = new TimeInterpolator() {
- @Override
- public float getInterpolation(float x) {
- return (float)(Math.cos((Math.pow(x,3) + 1) * Math.PI) / 2.0f) + 0.5f;
- }
- };
}
public void registerViews(View contentView, View saverView) {
@@ -242,58 +234,48 @@
mSaverView.setX(nextx);
mSaverView.setY(nexty);
ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f)
- .setDuration(FADE_TIME)
- .start();
+ .setDuration(FADE_TIME)
+ .start();
} else {
AnimatorSet s = new AnimatorSet();
- Animator xMove = ObjectAnimator.ofFloat(mSaverView,
- "x", mSaverView.getX(), nextx);
- Animator yMove = ObjectAnimator.ofFloat(mSaverView,
- "y", mSaverView.getY(), nexty);
+ Animator xMove = ObjectAnimator.ofFloat(mSaverView,
+ "x", mSaverView.getX(), nextx);
+ Animator yMove = ObjectAnimator.ofFloat(mSaverView,
+ "y", mSaverView.getY(), nexty);
Animator xShrink = ObjectAnimator.ofFloat(mSaverView, "scaleX", 1f, 0.85f);
- Animator xGrow = ObjectAnimator.ofFloat(mSaverView, "scaleX", 0.85f, 1f);
+ Animator xGrow = ObjectAnimator.ofFloat(mSaverView, "scaleX", 0.85f, 1f);
Animator yShrink = ObjectAnimator.ofFloat(mSaverView, "scaleY", 1f, 0.85f);
- Animator yGrow = ObjectAnimator.ofFloat(mSaverView, "scaleY", 0.85f, 1f);
- AnimatorSet shrink = new AnimatorSet(); shrink.play(xShrink).with(yShrink);
- AnimatorSet grow = new AnimatorSet(); grow.play(xGrow).with(yGrow);
+ Animator yGrow = ObjectAnimator.ofFloat(mSaverView, "scaleY", 0.85f, 1f);
+ AnimatorSet shrink = new AnimatorSet();
+ shrink.play(xShrink).with(yShrink);
+ AnimatorSet grow = new AnimatorSet();
+ grow.play(xGrow).with(yGrow);
Animator fadeout = ObjectAnimator.ofFloat(mSaverView, "alpha", 1f, 0f);
Animator fadein = ObjectAnimator.ofFloat(mSaverView, "alpha", 0f, 1f);
- if (SLIDE) {
- s.play(xMove).with(yMove);
- s.setDuration(SLIDE_TIME);
+ AccelerateInterpolator accel = new AccelerateInterpolator();
+ DecelerateInterpolator decel = new DecelerateInterpolator();
- s.play(shrink.setDuration(SLIDE_TIME/2));
- s.play(grow.setDuration(SLIDE_TIME/2)).after(shrink);
- s.setInterpolator(mSlowStartWithBrakes);
- } else {
- AccelerateInterpolator accel = new AccelerateInterpolator();
- DecelerateInterpolator decel = new DecelerateInterpolator();
-
- shrink.setDuration(FADE_TIME).setInterpolator(accel);
- fadeout.setDuration(FADE_TIME).setInterpolator(accel);
- grow.setDuration(FADE_TIME).setInterpolator(decel);
- fadein.setDuration(FADE_TIME).setInterpolator(decel);
- s.play(shrink);
- s.play(fadeout);
- s.play(xMove.setDuration(0)).after(FADE_TIME);
- s.play(yMove.setDuration(0)).after(FADE_TIME);
- s.play(fadein).after(FADE_TIME);
- s.play(grow).after(FADE_TIME);
- }
+ shrink.setDuration(FADE_TIME).setInterpolator(accel);
+ fadeout.setDuration(FADE_TIME).setInterpolator(accel);
+ grow.setDuration(FADE_TIME).setInterpolator(decel);
+ fadein.setDuration(FADE_TIME).setInterpolator(decel);
+ s.play(shrink);
+ s.play(fadeout);
+ s.play(xMove.setDuration(0)).after(FADE_TIME);
+ s.play(yMove.setDuration(0)).after(FADE_TIME);
+ s.play(fadein).after(FADE_TIME);
+ s.play(grow).after(FADE_TIME);
s.start();
}
long now = System.currentTimeMillis();
long adjust = (now % 60000);
- delay = delay
- + (MOVE_DELAY - adjust) // minute aligned
- - (SLIDE ? 0 : FADE_TIME) // start moving before the fade
- ;
+ delay = delay + (MOVE_DELAY - adjust) - (FADE_TIME); // start moving before the fade
}
mHandler.removeCallbacks(this);
@@ -301,44 +283,38 @@
}
}
- /** Setup to find out when the quarter-hour changes (e.g. Kathmandu is GMT+5:45) **/
+ /**
+ * Setup to find out when the quarter-hour changes (e.g. Kathmandu is GMT+5:45)
+ **/
public static long getAlarmOnQuarterHour() {
- final Calendar calendarInstance = Calendar.getInstance();
- final long now = System.currentTimeMillis();
- return getAlarmOnQuarterHour(calendarInstance, now);
+ return getAlarmOnQuarterHour(System.currentTimeMillis());
}
- static long getAlarmOnQuarterHour(Calendar calendar, long now) {
- // Set 1 second to ensure quarter-hour threshold passed.
- calendar.set(Calendar.SECOND, 1);
- calendar.set(Calendar.MILLISECOND, 0);
- int minute = calendar.get(Calendar.MINUTE);
- calendar.add(Calendar.MINUTE, 15 - (minute % 15));
- long alarmOnQuarterHour = calendar.getTimeInMillis();
-
- // Verify that alarmOnQuarterHour is within the next 15 minutes
- long delta = alarmOnQuarterHour - now;
- if (0 >= delta || delta > 901000) {
- // Something went wrong in the calculation, schedule something that is
- // about 15 minutes. Next time , it will align with the 15 minutes border.
- alarmOnQuarterHour = now + 901000;
- }
- return alarmOnQuarterHour;
+ @VisibleForTesting
+ static long getAlarmOnQuarterHour(long now) {
+ // Compute the time of the last quarter hour.
+ final long lastQuarterHour = now - (now % QUARTER_HOUR_IN_MILLIS);
+ // Add a quarter hour to move to the future.
+ final long nextQuarterHour = lastQuarterHour + QUARTER_HOUR_IN_MILLIS;
+ // Add an extra second to ensure callbacks are processed *after* the quarter hour passes.
+ return nextQuarterHour + DateUtils.SECOND_IN_MILLIS;
}
// Setup a thread that starts at midnight plus one second. The extra second is added to ensure
// the date has changed.
public static void setMidnightUpdater(Handler handler, Runnable runnable) {
- String timezone = TimeZone.getDefault().getID();
- if (handler == null || runnable == null || timezone == null) {
+ if (handler == null || runnable == null) {
return;
}
- long now = System.currentTimeMillis();
- Time time = new Time(timezone);
- time.set(now);
- long runInMillis = ((24 - time.hour) * 3600 - time.minute * 60 - time.second + 1) * 1000;
+
+ final Calendar c = Calendar.getInstance();
+ c.add(Calendar.DATE, 1);
+ c.set(Calendar.HOUR_OF_DAY, 0);
+ c.set(Calendar.MINUTE, 0);
+ c.set(Calendar.SECOND, 1);
+
handler.removeCallbacks(runnable);
- handler.postDelayed(runnable, runInMillis);
+ handler.postDelayed(runnable, c.getTimeInMillis() - System.currentTimeMillis());
}
// Stop the midnight update thread
@@ -420,7 +396,7 @@
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setColorFilter(new PorterDuffColorFilter(
- (dim ? 0x40FFFFFF : 0xC0FFFFFF),
+ (dim ? 0x40FFFFFF : 0xC0FFFFFF),
PorterDuff.Mode.MULTIPLY));
clockView.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
}
@@ -432,6 +408,7 @@
return isPreL() ? getNextAlarmPreL(context) : getNextAlarmLOrLater(context);
}
+ @SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.KITKAT)
private static String getNextAlarmPreL(Context context) {
final ContentResolver cr = context.getContentResolver();
@@ -458,7 +435,9 @@
return nextAlarmTimeMillis - System.currentTimeMillis() <= DateUtils.DAY_IN_MILLIS;
}
- /** Clock views can call this to refresh their alarm to the next upcoming value. */
+ /**
+ * Clock views can call this to refresh their alarm to the next upcoming value.
+ */
public static void refreshAlarm(Context context, View clock) {
final TextView nextAlarmView = (TextView) clock.findViewById(R.id.nextAlarm);
if (nextAlarmView == null) {
@@ -476,7 +455,9 @@
}
}
- /** Clock views can call this to refresh their date. **/
+ /**
+ * Clock views can call this to refresh their date.
+ **/
public static void updateDate(String dateSkeleton, String descriptionSkeleton, View clock) {
final TextView dateDisplay = (TextView) clock.findViewById(R.id.date);
if (dateDisplay == null) {
@@ -496,13 +477,14 @@
/***
* Formats the time in the TextClock according to the Locale with a special
* formatting treatment for the am/pm label.
+ *
* @param context - Context used to get user's locale and time preferences
- * @param clock - TextClock to format
+ * @param clock - TextClock to format
*/
public static void setTimeFormat(Context context, TextClock clock) {
if (clock != null) {
// Get the best format for 12 hours mode according to the locale
- clock.setFormat12Hour(get12ModeFormat(context, true /* showAmPm */));
+ clock.setFormat12Hour(get12ModeFormat(context, 0.4f /* amPmRatio */));
// Get the best format for 24 hours mode according to the locale
clock.setFormat24Hour(get24ModeFormat());
}
@@ -512,7 +494,7 @@
* Returns {@code true} if the am / pm strings for the current locale are long and a reduced
* text size should be used for displaying the digital clock.
*/
- public static boolean isAmPmStringLong() {
+ private static boolean isAmPmStringLong() {
final String[] amPmStrings = new DateFormatSymbols().getAmPmStrings();
for (String amPmString : amPmStrings) {
// Dots are small, so don't count them.
@@ -525,13 +507,14 @@
}
/**
- * @param context - context used to get time format string resource
- * @param showAmPm - include the am/pm string if true
+ * @param context used to get time format string resource
+ * @param amPmRatio a value between 0 and 1 that is the ratio of the relative size of the
+ * am/pm string to the time string
* @return format string for 12 hours mode time
*/
- public static CharSequence get12ModeFormat(Context context, boolean showAmPm) {
+ public static CharSequence get12ModeFormat(Context context, float amPmRatio) {
String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "hma");
- if (!showAmPm) {
+ if (amPmRatio <= 0) {
pattern = pattern.replaceAll("a", "").trim();
}
@@ -544,9 +527,8 @@
}
final Resources resources = context.getResources();
- final float amPmProportion = resources.getFraction(R.fraction.ampm_font_size_scale, 1, 1);
final Spannable sp = new SpannableString(pattern);
- sp.setSpan(new RelativeSizeSpan(amPmProportion), amPmPos, amPmPos + 1,
+ sp.setSpan(new RelativeSizeSpan(amPmRatio), amPmPos, amPmPos + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
sp.setSpan(new StyleSpan(Typeface.NORMAL), amPmPos, amPmPos + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -569,6 +551,7 @@
/**
* Returns string denoting the timezone hour offset (e.g. GMT -8:00)
+ *
* @param useShortForm Whether to return a short form of the header that rounds to the
* nearest hour and excludes the "GMT" prefix
*/
@@ -653,19 +636,16 @@
// nothing to do
return;
}
- if (sShortWeekdays == null) {
- sShortWeekdays = new String[DaysOfWeek.DAYS_IN_A_WEEK];
- }
- if (sLongWeekdays == null) {
- sLongWeekdays = new String[DaysOfWeek.DAYS_IN_A_WEEK];
- }
- final SimpleDateFormat shortFormat = new SimpleDateFormat(DATE_FORMAT_SHORT);
- final SimpleDateFormat longFormat = new SimpleDateFormat(DATE_FORMAT_LONG);
+ final Locale locale = Locale.getDefault();
+ final SimpleDateFormat shortFormat = new SimpleDateFormat(DATE_FORMAT_SHORT, locale);
+ final SimpleDateFormat longFormat = new SimpleDateFormat(DATE_FORMAT_LONG, locale);
+
+ sShortWeekdays = new String[DaysOfWeek.DAYS_IN_A_WEEK];
+ sLongWeekdays = new String[DaysOfWeek.DAYS_IN_A_WEEK];
// Create a date (2014/07/20) that is a Sunday
final long aSunday = new GregorianCalendar(2014, Calendar.JULY, 20).getTimeInMillis();
-
for (int i = 0; i < DaysOfWeek.DAYS_IN_A_WEEK; i++) {
final long dayMillis = aSunday + i * DateUtils.DAY_IN_MILLIS;
sShortWeekdays[i] = shortFormat.format(new Date(dayMillis));
@@ -676,16 +656,15 @@
sLocaleUsedForWeekdays = Locale.getDefault();
}
- /**
- * @param id Resource id of the plural
- * @param quantity integer value
- * @return string with properly localized numbers
- */
public static String getNumberFormattedQuantityString(Context context, int id, int quantity) {
final String localizedQuantity = NumberFormat.getInstance().format(quantity);
return context.getResources().getQuantityString(id, quantity, localizedQuantity);
}
+ /**
+ * {@link ArraySet} is @hide prior to {@link Build.VERSION_CODES#M}.
+ */
+ @SuppressLint("NewApi")
public static <E> ArraySet<E> newArraySet(Collection<E> collection) {
final ArraySet<E> arraySet = new ArraySet<>(collection.size());
arraySet.addAll(collection);
diff --git a/src/com/android/deskclock/VerticalViewPager.java b/src/com/android/deskclock/VerticalViewPager.java
index 5aaa41e..c7cdfe5 100644
--- a/src/com/android/deskclock/VerticalViewPager.java
+++ b/src/com/android/deskclock/VerticalViewPager.java
@@ -68,6 +68,22 @@
init();
}
+ /**
+ * @return {@code false} since a vertical view pager can never be scrolled horizontally
+ */
+ @Override
+ public boolean canScrollHorizontally(int direction) {
+ return false;
+ }
+
+ /**
+ * @return {@code true} iff a normal view pager would support horizontal scrolling at this time
+ */
+ @Override
+ public boolean canScrollVertically(int direction) {
+ return super.canScrollHorizontally(direction);
+ }
+
private void init() {
// Make page transit vertical
setPageTransformer(true, mPageTransformer);
@@ -85,8 +101,9 @@
case MotionEvent.ACTION_DOWN: {
mLastMotionX = x;
mLastMotionY = y;
- if (!mParentViewPager.onTouchEvent(ev))
+ if (!mParentViewPager.onTouchEvent(ev)) {
return false;
+ }
return verticalDrag(ev);
}
case MotionEvent.ACTION_MOVE: {
diff --git a/src/com/android/deskclock/actionbarmenu/ActionBarMenuManager.java b/src/com/android/deskclock/actionbarmenu/ActionBarMenuManager.java
index f470e5b..d2438e5 100644
--- a/src/com/android/deskclock/actionbarmenu/ActionBarMenuManager.java
+++ b/src/com/android/deskclock/actionbarmenu/ActionBarMenuManager.java
@@ -33,7 +33,7 @@
// A map of all menu item controllers, keyed by menu item id.
private final ArrayMap<Integer, MenuItemController> mControllers;
- public ActionBarMenuManager(Activity activity) {
+ public ActionBarMenuManager() {
mControllers = new ArrayMap<>();
}
diff --git a/src/com/android/deskclock/alarms/AlarmKlaxon.java b/src/com/android/deskclock/alarms/AlarmKlaxon.java
index 971c5e9..cf2bd88 100644
--- a/src/com/android/deskclock/alarms/AlarmKlaxon.java
+++ b/src/com/android/deskclock/alarms/AlarmKlaxon.java
@@ -58,7 +58,7 @@
}
if (instance.mVibrate) {
- final Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ final Vibrator vibrator = getVibrator(context);
if (Utils.isLOrLater()) {
vibrateLOrLater(vibrator);
} else {
@@ -77,6 +77,10 @@
.build());
}
+ private static Vibrator getVibrator(Context context) {
+ return ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE));
+ }
+
private static synchronized AsyncRingtonePlayer getAsyncRingtonePlayer(Context context) {
if (sAsyncRingtonePlayer == null) {
sAsyncRingtonePlayer = new AsyncRingtonePlayer(context.getApplicationContext(),
diff --git a/src/com/android/deskclock/alarms/AlarmNotifications.java b/src/com/android/deskclock/alarms/AlarmNotifications.java
index 3fff8e3..0140f08 100644
--- a/src/com/android/deskclock/alarms/AlarmNotifications.java
+++ b/src/com/android/deskclock/alarms/AlarmNotifications.java
@@ -260,11 +260,9 @@
}
public static Intent createViewAlarmIntent(Context context, AlarmInstance instance) {
- long alarmId = instance.mAlarmId == null ? Alarm.INVALID_ID : instance.mAlarmId;
- Intent viewAlarmIntent = Alarm.createIntent(context, DeskClock.class, alarmId);
- viewAlarmIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
- viewAlarmIntent.putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, alarmId);
- viewAlarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return viewAlarmIntent;
+ final long alarmId = instance.mAlarmId == null ? Alarm.INVALID_ID : instance.mAlarmId;
+ return Alarm.createIntent(context, DeskClock.class, alarmId)
+ .putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, alarmId)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
diff --git a/src/com/android/deskclock/alarms/AlarmStateManager.java b/src/com/android/deskclock/alarms/AlarmStateManager.java
index e31cea1..741c3d1 100644
--- a/src/com/android/deskclock/alarms/AlarmStateManager.java
+++ b/src/com/android/deskclock/alarms/AlarmStateManager.java
@@ -45,10 +45,13 @@
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
import com.android.deskclock.settings.SettingsActivity;
+import com.android.deskclock.uidata.UiDataModel;
import java.util.Calendar;
import java.util.List;
+import static com.android.deskclock.uidata.UiDataModel.Tab.ALARMS;
+
/**
* This class handles all the state changes for alarm instances. You need to
* register all alarm instances with the state manager if you want them to
@@ -206,6 +209,8 @@
/**
* Used in pre-L devices, where "next alarm" is stored in system settings.
*/
+ @SuppressWarnings("deprecation")
+ @TargetApi(Build.VERSION_CODES.KITKAT)
private static void updateNextAlarmInSystemSettings(Context context, AlarmInstance nextAlarm) {
// Send broadcast message so pre-L AppWidgets will recognize an update
String timeString = "";
@@ -283,8 +288,12 @@
Alarm.updateAlarm(cr, alarm);
}
} else {
- // Schedule the next repeating instance after the current time
- AlarmInstance nextRepeatedInstance = alarm.createInstanceAfter(getCurrentTime());
+ // Schedule the next repeating instance after the current time or the last instance's
+ // time (whichever is later).
+ final Calendar currentTime = getCurrentTime();
+ final Calendar lastInstanceTime = instance.getAlarmTime();
+ AlarmInstance nextRepeatedInstance = alarm.createInstanceAfter(
+ currentTime.compareTo(lastInstanceTime) > 0 ? currentTime : lastInstanceTime);
LogUtils.i("Creating new instance for repeating alarm " + alarm.id + " at " +
AlarmUtils.getFormattedTime(context, nextRepeatedInstance.getAlarmTime()));
AlarmInstance.addInstance(cr, nextRepeatedInstance);
@@ -574,13 +583,9 @@
scheduleInstanceStateChange(context, instance.getAlarmTime(), instance,
AlarmInstance.DISMISSED_STATE);
- final Alarm alarm = Alarm.getAlarm(contentResolver, instance.mAlarmId);
- // if it's a one time alarm set the toggle to off
- if (alarm != null && !alarm.daysOfWeek.isRepeating()) {
- // Check parent if it needs to reschedule, disable or delete itself
- if (instance.mAlarmId != null) {
- updateParentAlarm(context, instance);
- }
+ // Check parent if it needs to reschedule, disable or delete itself
+ if (instance.mAlarmId != null) {
+ updateParentAlarm(context, instance);
}
updateNextAlarm(context);
@@ -945,12 +950,17 @@
return;
}
+ // Change to the alarms tab.
+ UiDataModel.getUiDataModel().setSelectedTab(ALARMS);
+
long alarmId = instance.mAlarmId == null ? Alarm.INVALID_ID : instance.mAlarmId;
- Intent viewAlarmIntent = Alarm.createIntent(context, DeskClock.class, alarmId);
- viewAlarmIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
- viewAlarmIntent.putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, alarmId);
- viewAlarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Intent viewAlarmIntent = Alarm.createIntent(context, DeskClock.class, alarmId)
+ .putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, alarmId)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Open DeskClock which is now positioned on the alarms tab.
context.startActivity(viewAlarmIntent);
+
deleteInstanceAndUpdateParent(context, instance);
}
}
@@ -1002,7 +1012,12 @@
stateChangeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- am.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
+ if (Utils.isMOrLater()) {
+ // Ensure the alarm fires even if the device is dozing.
+ am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
+ } else {
+ am.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
+ }
}
@Override
diff --git a/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java b/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
index 5249003..fac9336 100644
--- a/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
+++ b/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
@@ -16,7 +16,9 @@
package com.android.deskclock.alarms;
+import android.app.DialogFragment;
import android.app.Fragment;
+import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +31,7 @@
import com.android.deskclock.LabelDialogFragment;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
+import com.android.deskclock.RingtonePickerDialogFragment;
import com.android.deskclock.alarms.utils.DayOrderUtils;
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
@@ -42,6 +45,7 @@
private static final String TAG = "AlarmTimeClickHandler";
private static final String KEY_PREVIOUS_DAY_MAP = "previousDayMap";
+ private static final String RINGTONE_PICKER_FRAG_TAG = "ringtone_picker_dialog";
private final Fragment mFragment;
private final AlarmUpdateHandler mAlarmUpdateHandler;
@@ -163,18 +167,28 @@
public void onRingtoneClicked(Alarm alarm) {
mSelectedAlarm = alarm;
- final Uri oldRingtone = Alarm.NO_RINGTONE_URI.equals(alarm.alert) ? null : alarm.alert;
- final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, oldRingtone);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM);
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
- LogUtils.d(TAG, "Showing ringtone picker.");
- mFragment.startActivityForResult(intent, R.id.request_code_ringtone);
+ final FragmentManager fragmentManager = mFragment.getFragmentManager();
+ fragmentManager.executePendingTransactions();
+ final FragmentTransaction ft = fragmentManager.beginTransaction();
+ final Fragment prev = fragmentManager.findFragmentByTag(RINGTONE_PICKER_FRAG_TAG);
+ if (prev != null) {
+ ft.remove(prev);
+ }
+ ft.addToBackStack(null);
+
+ final String dialogTitle = mFragment.getString(R.string.alert);
+ final String defaultTitle = mFragment.getString(R.string.default_alarm_ringtone_title);
+ final Uri defaultUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
+ final DialogFragment newFragment = RingtonePickerDialogFragment.newInstance(
+ dialogTitle, defaultTitle, defaultUri, alarm.alert, mFragment.getTag());
+ newFragment.show(ft, RINGTONE_PICKER_FRAG_TAG);
}
public void onEditLabelClicked(Alarm alarm) {
- final FragmentTransaction ft = mFragment.getFragmentManager().beginTransaction();
- final Fragment prev = mFragment.getFragmentManager().findFragmentByTag("label_dialog");
+ final FragmentManager fragmentManager = mFragment.getFragmentManager();
+ fragmentManager.executePendingTransactions();
+ final FragmentTransaction ft = fragmentManager.beginTransaction();
+ final Fragment prev = fragmentManager.findFragmentByTag("label_dialog");
if (prev != null) {
ft.remove(prev);
}
diff --git a/src/com/android/deskclock/alarms/dataadapter/AlarmItemHolder.java b/src/com/android/deskclock/alarms/dataadapter/AlarmItemHolder.java
new file mode 100644
index 0000000..f4e0129
--- /dev/null
+++ b/src/com/android/deskclock/alarms/dataadapter/AlarmItemHolder.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.alarms.dataadapter;
+
+import android.os.Bundle;
+
+import com.android.deskclock.ItemAdapter;
+import com.android.deskclock.alarms.AlarmTimeClickHandler;
+import com.android.deskclock.provider.Alarm;
+import com.android.deskclock.provider.AlarmInstance;
+
+public class AlarmItemHolder extends ItemAdapter.ItemHolder<Alarm> {
+
+ private static final java.lang.String EXPANDED_KEY = "expanded";
+ private final AlarmInstance mAlarmInstance;
+ private final AlarmTimeClickHandler mAlarmTimeClickHandler;
+ private boolean mExpanded;
+
+ public AlarmItemHolder(Alarm alarm, AlarmInstance alarmInstance,
+ AlarmTimeClickHandler alarmTimeClickHandler) {
+ super(alarm, alarm.id);
+ mAlarmInstance = alarmInstance;
+ mAlarmTimeClickHandler = alarmTimeClickHandler;
+ }
+
+ @Override
+ public int getItemViewType() {
+ return isExpanded() ?
+ ExpandedAlarmViewHolder.VIEW_TYPE : CollapsedAlarmViewHolder.VIEW_TYPE;
+ }
+
+ public AlarmTimeClickHandler getAlarmTimeClickHandler() {
+ return mAlarmTimeClickHandler;
+ }
+
+ public AlarmInstance getAlarmInstance() {
+ return mAlarmInstance;
+ }
+
+ public void expand() {
+ mExpanded = true;
+ notifyItemChanged();
+ }
+
+ public void collapse() {
+ mExpanded = false;
+ notifyItemChanged();
+ }
+
+ public boolean isExpanded() {
+ return mExpanded;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle bundle) {
+ super.onSaveInstanceState(bundle);
+ bundle.putBoolean(EXPANDED_KEY, mExpanded);
+ }
+
+ @Override
+ public void onRestoreInstanceState(Bundle bundle) {
+ super.onRestoreInstanceState(bundle);
+ mExpanded = bundle.getBoolean(EXPANDED_KEY);
+ }
+}
diff --git a/src/com/android/deskclock/alarms/dataadapter/AlarmItemViewHolder.java b/src/com/android/deskclock/alarms/dataadapter/AlarmItemViewHolder.java
new file mode 100644
index 0000000..40c450a
--- /dev/null
+++ b/src/com/android/deskclock/alarms/dataadapter/AlarmItemViewHolder.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.alarms.dataadapter;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.provider.Settings;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.deskclock.AlarmUtils;
+import com.android.deskclock.ItemAdapter;
+import com.android.deskclock.R;
+import com.android.deskclock.data.DataModel;
+import com.android.deskclock.provider.Alarm;
+import com.android.deskclock.provider.AlarmInstance;
+import com.android.deskclock.widget.TextTime;
+
+import java.util.Objects;
+
+/**
+ * Abstract ViewHolder for alarm time items.
+ */
+public abstract class AlarmItemViewHolder extends ItemAdapter.ItemViewHolder<AlarmItemHolder> {
+
+ private static final float CLOCK_ENABLED_ALPHA = 1f;
+ private static final float CLOCK_DISABLED_ALPHA = 0.69f;
+
+ public final TextTime clock;
+ public final CompoundButton onoff;
+ public final View arrow;
+ public final View preemptiveDismissContainer;
+ public final TextView preemptiveDismissButton;
+
+ private final TextView mAlarmMutedButton;
+ private final ContentObserver mVolumeObserver;
+
+ public AlarmItemViewHolder(final View itemView, Handler handler) {
+ super(itemView);
+
+ clock = (TextTime) itemView.findViewById(R.id.digital_clock);
+ onoff = (CompoundButton) itemView.findViewById(R.id.onoff);
+ arrow = itemView.findViewById(R.id.arrow);
+ preemptiveDismissContainer = itemView.findViewById(R.id.preemptive_dismiss_container);
+ preemptiveDismissButton =
+ (TextView) itemView.findViewById(R.id.preemptive_dismiss_button);
+ mAlarmMutedButton = (Button) itemView.findViewById(R.id.alarm_muted_button);
+
+ preemptiveDismissButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final AlarmInstance alarmInstance = getItemHolder().getAlarmInstance();
+ getItemHolder().getAlarmTimeClickHandler().dismissAlarmInstance(alarmInstance);
+ }
+ });
+ onoff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ getItemHolder().getAlarmTimeClickHandler().setAlarmEnabled(
+ getItemHolder().item, checked);
+ }
+ });
+ mAlarmMutedButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final Context context = itemView.getContext();
+ final Alarm alarm = getItemHolder().item;
+ if (hasSilentRingtone(alarm)) {
+ getItemHolder().getAlarmTimeClickHandler().onRingtoneClicked(alarm);
+ } else {
+ // Alarm volume muted.
+ final AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ audioManager.adjustStreamVolume(AudioManager.STREAM_ALARM,
+ AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
+ }
+ }
+ });
+ mVolumeObserver = new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (getItemHolder() != null) {
+ getItemHolder().notifyItemChanged();
+ }
+ }
+ };
+ }
+
+ @Override
+ protected void onBindItemView(final AlarmItemHolder itemHolder) {
+ final Context context = itemView.getContext();
+ final Alarm alarm = itemHolder.item;
+ bindOnOffSwitch(alarm);
+ bindAlarmMutedButton(context, alarm);
+ bindClock(context, alarm);
+ context.getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mVolumeObserver);
+ }
+
+ @Override
+ protected void onRecycleItemView() {
+ itemView.getContext().getContentResolver().unregisterContentObserver(mVolumeObserver);
+ }
+
+ protected void bindOnOffSwitch(Alarm alarm) {
+ onoff.setChecked(alarm.enabled);
+ }
+
+ protected void bindClock(Context context, Alarm alarm) {
+ clock.setAlpha(alarm.enabled ? CLOCK_ENABLED_ALPHA : CLOCK_DISABLED_ALPHA);
+ clock.setFormat(context);
+ clock.setTime(alarm.hour, alarm.minutes);
+ }
+
+ protected boolean bindPreemptiveDismissButton(Context context, Alarm alarm,
+ AlarmInstance alarmInstance) {
+
+ final AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ final boolean muted = audioManager.getStreamVolume(AudioManager.STREAM_ALARM) == 0
+ || hasSilentRingtone(alarm);
+ final boolean canBind = alarm.canPreemptivelyDismiss() && alarmInstance != null && !muted;
+
+ if (canBind) {
+ preemptiveDismissContainer.setVisibility(View.VISIBLE);
+ final String dismissText = alarm.instanceState == AlarmInstance.SNOOZE_STATE
+ ? context.getString(R.string.alarm_alert_snooze_until,
+ AlarmUtils.getAlarmText(context, alarmInstance, false))
+ : context.getString(R.string.alarm_alert_dismiss_now_text);
+ preemptiveDismissButton.setText(dismissText);
+ } else {
+ preemptiveDismissContainer.setVisibility(View.GONE);
+ }
+ return canBind;
+ }
+
+ protected void bindAlarmMutedButton(Context context, Alarm alarm) {
+ final AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ if (hasSilentRingtone(alarm)) {
+ mAlarmMutedButton.setVisibility(View.VISIBLE);
+ mAlarmMutedButton.setText(R.string.silent_ringtone);
+ } else if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) == 0) {
+ mAlarmMutedButton.setVisibility(View.VISIBLE);
+ mAlarmMutedButton.setText(R.string.alarm_volume_muted);
+ } else {
+ mAlarmMutedButton.setVisibility(View.GONE);
+ }
+ }
+
+ private boolean hasSilentRingtone(Alarm alarm) {
+ return Objects.equals(alarm.alert, DataModel.getDataModel().getSilentRingtoneUri());
+ }
+}
diff --git a/src/com/android/deskclock/alarms/dataadapter/AlarmTimeAdapter.java b/src/com/android/deskclock/alarms/dataadapter/AlarmTimeAdapter.java
deleted file mode 100644
index 15d1f4e..0000000
--- a/src/com/android/deskclock/alarms/dataadapter/AlarmTimeAdapter.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.deskclock.alarms.dataadapter;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.os.Vibrator;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.deskclock.LogUtils;
-import com.android.deskclock.R;
-import com.android.deskclock.alarms.AlarmTimeClickHandler;
-import com.android.deskclock.alarms.ScrollHandler;
-import com.android.deskclock.provider.Alarm;
-import com.android.deskclock.provider.AlarmInstance;
-
-/**
- * Data adapter for alarm time items.
- */
-public final class AlarmTimeAdapter extends RecyclerView.Adapter<AlarmTimeViewHolder> {
- private static final String TAG = "CwAlarm";
- private static final String KEY_EXPANDED_ID = "expandedId";
- private static final int VIEW_TYPE_ALARM_TIME_COLLAPSED = R.layout.alarm_time_collapsed;
- private static final int VIEW_TYPE_ALARM_TIME_EXPANDED = R.layout.alarm_time_expanded;
-
- private final Context mContext;
- private final LayoutInflater mInflater;
-
- private final AlarmTimeClickHandler mAlarmTimeClickHandler;
- private final ScrollHandler mScrollHandler;
-
- private final boolean mHasVibrator;
- private int mExpandedPosition = -1;
- private long mExpandedId = Alarm.INVALID_ID;
- private Cursor mCursor;
-
- public AlarmTimeAdapter(Context context, Bundle savedState,
- AlarmTimeClickHandler alarmTimeClickHandler, ScrollHandler smoothScrollController) {
- mContext = context;
- mInflater = LayoutInflater.from(context);
- mScrollHandler = smoothScrollController;
- mAlarmTimeClickHandler = alarmTimeClickHandler;
- mHasVibrator = ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
- .hasVibrator();
- if (savedState != null) {
- mExpandedId = savedState.getLong(KEY_EXPANDED_ID, Alarm.INVALID_ID);
- }
-
- setHasStableIds(true);
- }
-
- @Override
- public AlarmTimeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- final View v = mInflater.inflate(viewType, parent, false /* attachToRoot */);
- if (viewType == VIEW_TYPE_ALARM_TIME_COLLAPSED) {
- return new CollapsedAlarmViewHolder(v, mAlarmTimeClickHandler, this);
- } else {
- return new ExpandedAlarmViewHolder(v, mHasVibrator, mAlarmTimeClickHandler, this);
- }
- }
-
- @Override
- public void onViewRecycled(AlarmTimeViewHolder viewHolder) {
- super.onViewRecycled(viewHolder);
- viewHolder.clearData();
- }
-
- @Override
- public void onBindViewHolder(AlarmTimeViewHolder viewHolder, int position) {
- if (!mCursor.moveToPosition(position)) {
- LogUtils.e(TAG, "Failed to bind alarm " + position);
- return;
- }
- final Alarm alarm = new Alarm(mCursor);
- final AlarmInstance alarmInstance = alarm.canPreemptivelyDismiss()
- ? new AlarmInstance(mCursor, true /* joinedTable */) : null;
- viewHolder.bindAlarm(mContext, alarm, alarmInstance);
- }
-
- @Override
- public int getItemCount() {
- return mCursor == null ? 0 : mCursor.getCount();
- }
-
- @Override
- public long getItemId(int position) {
- if (mCursor == null || !mCursor.moveToPosition(position)) {
- return RecyclerView.NO_ID;
- }
- // TODO: Directly read id instead of instantiating Alarm object.
- return new Alarm(mCursor).id;
- }
-
- @Override
- public int getItemViewType(int position) {
- final long stableId = getItemId(position);
- return stableId != RecyclerView.NO_ID && stableId == mExpandedId
- ? VIEW_TYPE_ALARM_TIME_EXPANDED : VIEW_TYPE_ALARM_TIME_COLLAPSED;
- }
-
- public void saveInstance(Bundle outState) {
- outState.putLong(KEY_EXPANDED_ID, mExpandedId);
- }
-
- /**
- * Request the UI to expand the alarm at selected position and scroll it into view.
- */
- public void expand(int position) {
- final long stableId = getItemId(position);
- if (mExpandedId == stableId) {
- return;
- }
- mExpandedId = stableId;
- mScrollHandler.smoothScrollTo(position);
- if (mExpandedPosition >= 0) {
- notifyItemChanged(mExpandedPosition);
- }
- mExpandedPosition = position;
- notifyItemChanged(position);
- }
-
- public void collapse(int position) {
- mExpandedId = Alarm.INVALID_ID;
- mExpandedPosition = -1;
- notifyItemChanged(position);
- }
-
- /**
- * Swaps the adapter to a new data source.
- *
- * @param cursor A cursor generated by Cursor loader from {@link Alarm#getAlarmsCursorLoader}.
- */
- public void swapCursor(Cursor cursor) {
- if (mCursor == cursor) {
- return;
- }
- if (mCursor != null) {
- mCursor.close();
- }
- mCursor = cursor;
- notifyDataSetChanged();
- }
-}
diff --git a/src/com/android/deskclock/alarms/dataadapter/AlarmTimeViewHolder.java b/src/com/android/deskclock/alarms/dataadapter/AlarmTimeViewHolder.java
deleted file mode 100644
index b23eebb..0000000
--- a/src/com/android/deskclock/alarms/dataadapter/AlarmTimeViewHolder.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.deskclock.alarms.dataadapter;
-
-import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SwitchCompat;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.TextView;
-
-import com.android.deskclock.AlarmUtils;
-import com.android.deskclock.R;
-import com.android.deskclock.alarms.AlarmTimeClickHandler;
-import com.android.deskclock.provider.Alarm;
-import com.android.deskclock.provider.AlarmInstance;
-import com.android.deskclock.widget.TextTime;
-
-/**
- * Abstract ViewHolder for alarm time items.
- */
-public abstract class AlarmTimeViewHolder extends RecyclerView.ViewHolder {
-
- private static final float CLOCK_ENABLED_ALPHA = 1f;
- private static final float CLOCK_DISABLED_ALPHA = 0.69f;
-
- public final TextTime clock;
- public final CompoundButton onoff;
- public final View arrow;
- public final View preemptiveDismissContainer;
- public final TextView preemptiveDismissButton;
-
- protected Alarm mAlarm;
- protected AlarmInstance mAlarmInstance;
-
- private final AlarmTimeClickHandler mAlarmTimeClickHandler;
-
- public AlarmTimeViewHolder(View itemView, AlarmTimeClickHandler alarmTimeClickHandler) {
- super(itemView);
- mAlarmTimeClickHandler = alarmTimeClickHandler;
- clock = (TextTime) itemView.findViewById(R.id.digital_clock);
- onoff = (CompoundButton) itemView.findViewById(R.id.onoff);
- arrow = itemView.findViewById(R.id.arrow);
- preemptiveDismissContainer = itemView.findViewById(R.id.preemptive_dismiss_container);
- preemptiveDismissButton =
- (TextView) itemView.findViewById(R.id.preemptive_dismiss_button);
- preemptiveDismissButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mAlarmTimeClickHandler.dismissAlarmInstance(mAlarmInstance);
- }
- });
- onoff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
- mAlarmTimeClickHandler.setAlarmEnabled(mAlarm, checked);
- }
- });
- }
-
- public void setData(Alarm alarm, AlarmInstance alarmInstance) {
- mAlarmInstance = alarmInstance;
- mAlarm = alarm;
- }
-
- public void clearData() {
- mAlarmInstance = null;
- mAlarm = null;
- }
-
- /**
- * Binds the view with {@link Alarm} data.
- */
- public abstract void bindAlarm(Context context, Alarm alarm, AlarmInstance alarmInstance);
-
- protected void bindOnOffSwitch(Context context, Alarm alarm) {
- onoff.setChecked(alarm.enabled);
- ((SwitchCompat) onoff).setTextOn(context.getString(R.string.on_switch));
- ((SwitchCompat) onoff).setTextOff(context.getString(R.string.off_switch));
- }
-
- protected void bindClock(Context context, Alarm alarm) {
- clock.setAlpha(alarm.enabled ? CLOCK_ENABLED_ALPHA : CLOCK_DISABLED_ALPHA);
- clock.setFormat(context);
- clock.setTime(alarm.hour, alarm.minutes);
- }
-
- protected boolean bindPreemptiveDismissButton(Context context, Alarm alarm,
- AlarmInstance alarmInstance) {
- boolean canBind = alarm.canPreemptivelyDismiss() && alarmInstance != null;
- if (canBind) {
- preemptiveDismissContainer.setVisibility(View.VISIBLE);
- final String dismissText = alarm.instanceState == AlarmInstance.SNOOZE_STATE
- ? context.getString(R.string.alarm_alert_snooze_until,
- AlarmUtils.getAlarmText(context, alarmInstance, false))
- : context.getString(R.string.alarm_alert_dismiss_now_text);
- preemptiveDismissButton.setText(dismissText);
- } else {
- preemptiveDismissContainer.setVisibility(View.GONE);
- }
- return canBind;
- }
-}
diff --git a/src/com/android/deskclock/alarms/dataadapter/CollapsedAlarmViewHolder.java b/src/com/android/deskclock/alarms/dataadapter/CollapsedAlarmViewHolder.java
index 6db8878..0eb833c 100644
--- a/src/com/android/deskclock/alarms/dataadapter/CollapsedAlarmViewHolder.java
+++ b/src/com/android/deskclock/alarms/dataadapter/CollapsedAlarmViewHolder.java
@@ -17,13 +17,17 @@
package com.android.deskclock.alarms.dataadapter;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.text.TextUtils;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.TextView;
+import com.android.deskclock.ItemAdapter;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
-import com.android.deskclock.alarms.AlarmTimeClickHandler;
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
@@ -32,17 +36,17 @@
/**
* A ViewHolder containing views for an alarm item in collapsed stated.
*/
-public final class CollapsedAlarmViewHolder extends AlarmTimeViewHolder {
+public final class CollapsedAlarmViewHolder extends AlarmItemViewHolder {
+
+ public static final int VIEW_TYPE = R.layout.alarm_time_collapsed;
public final TextView alarmLabel;
public final TextView daysOfWeek;
public final TextView upcomingInstanceLabel;
public final View hairLine;
- public CollapsedAlarmViewHolder(View itemView,
- final AlarmTimeClickHandler alarmTimeClickHandler,
- final AlarmTimeAdapter alarmTimeAdapter) {
- super(itemView, alarmTimeClickHandler);
+ public CollapsedAlarmViewHolder(View itemView, Handler handler) {
+ super(itemView, handler);
alarmLabel = (TextView) itemView.findViewById(R.id.label);
daysOfWeek = (TextView) itemView.findViewById(R.id.days_of_week);
upcomingInstanceLabel = (TextView) itemView.findViewById(R.id.upcoming_instance_label);
@@ -52,36 +56,37 @@
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeAdapter.expand(getAdapterPosition());
+ getItemHolder().expand();
}
});
alarmLabel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeAdapter.expand(getAdapterPosition());
+ getItemHolder().expand();
}
});
arrow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeAdapter.expand(getAdapterPosition());
+ getItemHolder().expand();
}
});
// Edit time handler
clock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeClickHandler.onClockClicked(mAlarm);
- alarmTimeAdapter.expand(getAdapterPosition());
+ getItemHolder().getAlarmTimeClickHandler().onClockClicked(getItemHolder().item);
+ getItemHolder().expand();
}
});
}
@Override
- public void bindAlarm(Context context, Alarm alarm, AlarmInstance alarmInstance) {
- setData(alarm, alarmInstance);
- bindOnOffSwitch(context, alarm);
- bindClock(context, alarm);
+ protected void onBindItemView(AlarmItemHolder itemHolder) {
+ super.onBindItemView(itemHolder);
+ final Alarm alarm = itemHolder.item;
+ final AlarmInstance alarmInstance = itemHolder.getAlarmInstance();
+ final Context context = itemView.getContext();
bindRepeatText(context, alarm);
bindReadOnlyLabel(context, alarm);
bindUpcomingInstance(context, alarm);
@@ -127,4 +132,21 @@
upcomingInstanceLabel.setText(labelText);
}
}
+
+ public static class Factory implements ItemAdapter.ItemViewHolder.Factory {
+
+ private final LayoutInflater mLayoutInflater;
+ private final Handler mHandler;
+
+ public Factory(LayoutInflater layoutInflater) {
+ mLayoutInflater = layoutInflater;
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ @Override
+ public ItemAdapter.ItemViewHolder<?> createViewHolder(ViewGroup parent, int viewType) {
+ return new CollapsedAlarmViewHolder(mLayoutInflater.inflate(
+ viewType, parent, false /* attachToRoot */), mHandler);
+ }
+ }
}
diff --git a/src/com/android/deskclock/alarms/dataadapter/ExpandedAlarmViewHolder.java b/src/com/android/deskclock/alarms/dataadapter/ExpandedAlarmViewHolder.java
index c4c9bb0..26db82f 100644
--- a/src/com/android/deskclock/alarms/dataadapter/ExpandedAlarmViewHolder.java
+++ b/src/com/android/deskclock/alarms/dataadapter/ExpandedAlarmViewHolder.java
@@ -19,16 +19,23 @@
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Vibrator;
+import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.Button;
+import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.deskclock.ItemAdapter;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import com.android.deskclock.alarms.AlarmTimeClickHandler;
@@ -43,7 +50,9 @@
/**
* A ViewHolder containing views for an alarm item in expanded stated.
*/
-public final class ExpandedAlarmViewHolder extends AlarmTimeViewHolder {
+public final class ExpandedAlarmViewHolder extends AlarmItemViewHolder {
+
+ public static final int VIEW_TYPE = R.layout.alarm_time_expanded;
public final CheckBox repeat;
public final TextView editLabel;
@@ -51,18 +60,14 @@
public final CompoundButton[] dayButtons = new CompoundButton[7];
public final CheckBox vibrate;
public final TextView ringtone;
- public final Button delete;
- public final View preemptiveDismissContainer;
- public final TextView preemptiveDismissButton;
+ public final ImageButton delete;
private final boolean mHasVibrator;
private final int[] mDayOrder;
- public ExpandedAlarmViewHolder(View itemView,
- final boolean hasVibrator,
- final AlarmTimeClickHandler alarmTimeClickHandler,
- final AlarmTimeAdapter alarmTimeAdapter) {
- super(itemView, alarmTimeClickHandler);
+ public ExpandedAlarmViewHolder(View itemView, final boolean hasVibrator, Handler handler) {
+ super(itemView, handler);
+
final Context context = itemView.getContext();
mHasVibrator = hasVibrator;
mDayOrder = DayOrderUtils.getDayOrder(context);
@@ -71,14 +76,14 @@
final TypedArray typedArray = theme.obtainStyledAttributes(attrs);
final LayerDrawable background = new LayerDrawable(new Drawable[] {
- context.getResources().getDrawable(R.drawable.alarm_background_expanded),
+ ContextCompat.getDrawable(context, R.drawable.alarm_background_expanded),
typedArray.getDrawable(0) });
itemView.setBackground(background);
typedArray.recycle();
final int firstDay = Utils.getZeroIndexedFirstDayOfWeek(context);
- delete = (Button) itemView.findViewById(R.id.delete);
+ delete = (ImageButton) itemView.findViewById(R.id.delete);
repeat = (CheckBox) itemView.findViewById(R.id.repeat_onoff);
vibrate = (CheckBox) itemView.findViewById(R.id.vibrate_onoff);
@@ -97,56 +102,53 @@
dayButtons[i] = dayButton;
}
- preemptiveDismissContainer = itemView.findViewById(R.id.preemptive_dismiss_container);
- preemptiveDismissButton =
- (TextView) itemView.findViewById(R.id.preemptive_dismiss_button);
-
// Collapse handler
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeAdapter.collapse(getAdapterPosition());
+ getItemHolder().collapse();
}
});
arrow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeAdapter.collapse(getAdapterPosition());
+ getItemHolder().collapse();
}
});
// Edit time handler
clock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeClickHandler.onClockClicked(mAlarm);
+ getAlarmTimeClickHandler().onClockClicked(getItemHolder().item);
}
});
// Edit label handler
editLabel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- alarmTimeClickHandler.onEditLabelClicked(mAlarm);
+ getAlarmTimeClickHandler().onEditLabelClicked(getItemHolder().item);
}
});
// Vibrator checkbox handler
vibrate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeClickHandler.setAlarmVibrationEnabled(mAlarm, ((CheckBox) v).isChecked());
+ getAlarmTimeClickHandler().setAlarmVibrationEnabled(getItemHolder().item,
+ ((CheckBox) v).isChecked());
}
});
// Ringtone editor handler
ringtone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- alarmTimeClickHandler.onRingtoneClicked(mAlarm);
+ getAlarmTimeClickHandler().onRingtoneClicked(getItemHolder().item);
}
});
// Delete alarm handler
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- alarmTimeClickHandler.onDeleteClicked(mAlarm);
+ getAlarmTimeClickHandler().onDeleteClicked(getItemHolder().item);
v.announceForAccessibility(context.getString(R.string.alarm_deleted));
}
});
@@ -155,7 +157,7 @@
@Override
public void onClick(View view) {
final boolean checked = ((CheckBox) view).isChecked();
- alarmTimeClickHandler.setAlarmRepeatEnabled(mAlarm, checked);
+ getAlarmTimeClickHandler().setAlarmRepeatEnabled(getItemHolder().item, checked);
}
});
// Day buttons handler
@@ -165,17 +167,19 @@
@Override
public void onClick(View view) {
final boolean isChecked = ((CompoundButton) view).isChecked();
- alarmTimeClickHandler.setDayOfWeekEnabled(mAlarm, isChecked, buttonIndex);
+ getAlarmTimeClickHandler().setDayOfWeekEnabled(getItemHolder().item,
+ isChecked, buttonIndex);
}
});
}
}
@Override
- public void bindAlarm(Context context, Alarm alarm, AlarmInstance alarmInstance) {
- setData(alarm, alarmInstance);
- bindOnOffSwitch(context, alarm);
- bindClock(context, alarm);
+ protected void onBindItemView(final AlarmItemHolder itemHolder) {
+ super.onBindItemView(itemHolder);
+ final Alarm alarm = itemHolder.item;
+ final AlarmInstance alarmInstance = itemHolder.getAlarmInstance();
+ final Context context = itemView.getContext();
bindEditLabel(alarm);
bindDaysOfWeekButtons(alarm);
bindVibrator(alarm);
@@ -200,8 +204,7 @@
dayButton.setTextColor(Utils.getCurrentHourColor());
} else {
dayButton.setChecked(false);
- dayButton.setTextColor(itemView.getContext().getResources().getColor(R.color
- .white));
+ dayButton.setTextColor(Color.WHITE);
}
}
if (alarm.daysOfWeek.isRepeating()) {
@@ -229,4 +232,28 @@
vibrate.setChecked(alarm.vibrate);
}
}
+
+ private AlarmTimeClickHandler getAlarmTimeClickHandler() {
+ return getItemHolder().getAlarmTimeClickHandler();
+ }
+
+ public static class Factory implements ItemAdapter.ItemViewHolder.Factory {
+
+ private final LayoutInflater mLayoutInflator;
+ private final Handler mHandler;
+ private final boolean mHasVibrator;
+
+ public Factory(Context context, LayoutInflater layoutInflater) {
+ mLayoutInflator = layoutInflater;
+ mHandler = new Handler(Looper.getMainLooper());
+ mHasVibrator =
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator();
+ }
+
+ @Override
+ public ItemAdapter.ItemViewHolder<?> createViewHolder(ViewGroup parent, int viewType) {
+ return new ExpandedAlarmViewHolder(mLayoutInflator.inflate(
+ viewType, parent, false /* attachToRoot */), mHasVibrator, mHandler);
+ }
+ }
}
diff --git a/src/com/android/deskclock/data/AlarmModel.java b/src/com/android/deskclock/data/AlarmModel.java
index 750b72b..0ae5a0b 100644
--- a/src/com/android/deskclock/data/AlarmModel.java
+++ b/src/com/android/deskclock/data/AlarmModel.java
@@ -67,8 +67,11 @@
}
void setDefaultAlarmRingtoneUri(Uri uri) {
- mSettingsModel.setDefaultAlarmRingtoneUri(uri);
- mDefaultAlarmRingtoneUri = uri;
+ // Never set the silent ringtone as default; new alarms should always make sound by default.
+ if (!Alarm.NO_RINGTONE_URI.equals(uri)) {
+ mSettingsModel.setDefaultAlarmRingtoneUri(uri);
+ mDefaultAlarmRingtoneUri = uri;
+ }
}
String getAlarmRingtoneTitle(Uri uri) {
diff --git a/src/com/android/deskclock/data/City.java b/src/com/android/deskclock/data/City.java
index a5fd850..0463e8a 100644
--- a/src/com/android/deskclock/data/City.java
+++ b/src/com/android/deskclock/data/City.java
@@ -50,6 +50,12 @@
/** A cached upper case form of the {@link #mName} used in case-insensitive name comparisons. */
private String mNameUpperCase;
+ /**
+ * A cached upper case form of the {@link #mName} used in case-insensitive name comparisons
+ * which ignore {@link #removeSpecialCharacters(String)} special characters.
+ */
+ private String mNameUpperCaseNoSpecialCharacters;
+
City(String id, int index, String indexString, String name, String phoneticName,
String timeZoneId) {
mId = id;
@@ -69,6 +75,9 @@
public String getIndexString() { return mIndexString; }
public String getPhoneticName() { return mPhoneticName; }
+ /**
+ * @return the city name converted to upper case
+ */
public String getNameUpperCase() {
if (mNameUpperCase == null) {
mNameUpperCase = mName.toUpperCase();
@@ -76,6 +85,27 @@
return mNameUpperCase;
}
+ /**
+ * @return the city name converted to upper case with all special characters removed
+ */
+ private String getNameUpperCaseNoSpecialCharacters() {
+ if (mNameUpperCaseNoSpecialCharacters == null) {
+ mNameUpperCaseNoSpecialCharacters = removeSpecialCharacters(getNameUpperCase());
+ }
+ return mNameUpperCaseNoSpecialCharacters;
+ }
+
+ /**
+ * @param upperCaseQueryNoSpecialCharacters search term with all special characters removed
+ * to match against the upper case city name
+ * @return {@code true} iff the name of this city starts with the given query
+ */
+ public boolean matches(String upperCaseQueryNoSpecialCharacters) {
+ // By removing all special characters, prefix matching becomes more liberal and it is easier
+ // to locate the desired city. e.g. "St. Lucia" is matched by "StL", "St.L", "St L", "St. L"
+ return getNameUpperCaseNoSpecialCharacters().startsWith(upperCaseQueryNoSpecialCharacters);
+ }
+
@Override
public String toString() {
return String.format("City {id=%s, index=%d, indexString=%s, name=%s, phonetic=%s, tz=%s}",
@@ -83,6 +113,17 @@
}
/**
+ * Strips out any characters considered optional for matching purposes. These include spaces,
+ * dashes, periods and apostrophes.
+ *
+ * @param token a city name or search term
+ * @return the given {@code token} without any characters considered optional when matching
+ */
+ public static String removeSpecialCharacters(String token) {
+ return token.replaceAll("[ -.']", "");
+ }
+
+ /**
* Orders by:
*
* <ol>
diff --git a/src/com/android/deskclock/data/CityModel.java b/src/com/android/deskclock/data/CityModel.java
index 4f88029..ec987bc 100644
--- a/src/com/android/deskclock/data/CityModel.java
+++ b/src/com/android/deskclock/data/CityModel.java
@@ -52,9 +52,11 @@
* Retain a hard reference to the shared preference observer to prevent it from being garbage
* collected. See {@link SharedPreferences#registerOnSharedPreferenceChangeListener} for detail.
*/
+ @SuppressWarnings("FieldCanBeLocal")
private final OnSharedPreferenceChangeListener mPreferenceListener = new PreferenceListener();
/** Clears data structures containing data that is locale-sensitive. */
+ @SuppressWarnings("FieldCanBeLocal")
private final BroadcastReceiver mLocaleChangedReceiver = new LocaleChangedReceiver();
/** Maps city ID to city instance. */
@@ -269,4 +271,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/data/DataModel.java b/src/com/android/deskclock/data/DataModel.java
index 382beb3..58e92b0 100644
--- a/src/com/android/deskclock/data/DataModel.java
+++ b/src/com/android/deskclock/data/DataModel.java
@@ -149,6 +149,7 @@
* @return {@code true} when the application is open in the foreground; {@code false} otherwise
*/
public boolean isApplicationInForeground() {
+ enforceMainLooper();
return mNotificationModel.isApplicationInForeground();
}
@@ -157,10 +158,16 @@
* be rebuilt. e.g. after upgrading the application
*/
public void updateAllNotifications() {
+ enforceMainLooper();
mTimerModel.updateNotification();
mStopwatchModel.updateNotification();
}
+ public Uri getSilentRingtoneUri() {
+ enforceMainLooper();
+ return Uri.EMPTY;
+ }
+
//
// Cities
//
@@ -343,10 +350,11 @@
*
* @param timer the timer to be reset
* @param eventLabelId the label of the timer event to send; 0 if no event should be sent
+ * @return the reset {@code timer} or {@code null} if the timer was deleted
*/
- public void resetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
+ public Timer resetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
enforceMainLooper();
- mTimerModel.resetOrDeleteTimer(timer, eventLabelId);
+ return mTimerModel.resetOrDeleteTimer(timer, eventLabelId);
}
/**
@@ -429,6 +437,14 @@
}
/**
+ * @param uri the uri of the ringtone to play for all timers
+ */
+ public void setTimerRingtoneUri(Uri uri) {
+ enforceMainLooper();
+ mTimerModel.setTimerRingtoneUri(uri);
+ }
+
+ /**
* @return the title of the ringtone that is played for all timers
*/
public String getTimerRingtoneTitle() {
@@ -436,6 +452,22 @@
return mTimerModel.getTimerRingtoneTitle();
}
+ /**
+ * @return whether vibrate is enabled for all timers.
+ */
+ public boolean getTimerVibrate() {
+ enforceMainLooper();
+ return mTimerModel.getTimerVibrate();
+ }
+
+ /**
+ * @param enabled whether vibrate is enabled for all timers.
+ */
+ public void setTimerVibrate(boolean enabled) {
+ enforceMainLooper();
+ mTimerModel.setTimerVibrate(enabled);
+ }
+
//
// Alarms
//
@@ -605,4 +637,4 @@
return mExecuted;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/data/SettingsDAO.java b/src/com/android/deskclock/data/SettingsDAO.java
index 33ede47..192874b 100644
--- a/src/com/android/deskclock/data/SettingsDAO.java
+++ b/src/com/android/deskclock/data/SettingsDAO.java
@@ -120,6 +120,30 @@
}
/**
+ * @return whether timer vibration is enabled. false by default.
+ */
+ static boolean getTimerVibrate(Context context) {
+ final SharedPreferences prefs = getSharedPreferences(context);
+ return prefs.getBoolean(SettingsActivity.KEY_TIMER_VIBRATE, false);
+ }
+
+ /**
+ * @param enabled whether vibration will be turned on for all timers.
+ */
+ static void setTimerVibrate(Context context, boolean enabled) {
+ final SharedPreferences prefs = getSharedPreferences(context);
+ prefs.edit().putBoolean(SettingsActivity.KEY_TIMER_VIBRATE, enabled).apply();
+ }
+
+ /**
+ * @param uri the uri of the ringtone to play for all timers
+ */
+ static void setTimerRingtoneUri(Context context, Uri uri) {
+ final SharedPreferences prefs = getSharedPreferences(context);
+ prefs.edit().putString(SettingsActivity.KEY_TIMER_RINGTONE, uri.toString()).apply();
+ }
+
+ /**
* @return the uri of the selected ringtone or the {@code defaultUri} if no explicit selection
* has yet been made
*/
@@ -128,7 +152,6 @@
final String uriString = prefs.getString(KEY_DEFAULT_ALARM_RINGTONE_URI, null);
return uriString == null ? defaultUri : Uri.parse(uriString);
}
-
/**
* @param uri identifies the default ringtone to play for new alarms
*/
diff --git a/src/com/android/deskclock/data/SettingsModel.java b/src/com/android/deskclock/data/SettingsModel.java
index 224f190..24649bf 100644
--- a/src/com/android/deskclock/data/SettingsModel.java
+++ b/src/com/android/deskclock/data/SettingsModel.java
@@ -86,6 +86,10 @@
return mDefaultTimerRingtoneUri;
}
+ void setTimerRingtoneUri(Uri uri) {
+ SettingsDAO.setTimerRingtoneUri(mContext, uri);
+ }
+
Uri getTimerRingtoneUri() {
return SettingsDAO.getTimerRingtoneUri(mContext, getDefaultTimerRingtoneUri());
}
@@ -98,4 +102,12 @@
void setDefaultAlarmRingtoneUri(Uri uri) {
SettingsDAO.setDefaultAlarmRingtoneUri(mContext, uri);
}
+
+ boolean getTimerVibrate() {
+ return SettingsDAO.getTimerVibrate(mContext);
+ }
+
+ void setTimerVibrate(boolean enabled) {
+ SettingsDAO.setTimerVibrate(mContext, enabled);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/deskclock/data/TimerModel.java b/src/com/android/deskclock/data/TimerModel.java
index 877af10..ebc7eb2 100644
--- a/src/com/android/deskclock/data/TimerModel.java
+++ b/src/com/android/deskclock/data/TimerModel.java
@@ -270,9 +270,10 @@
*
* @param timer the timer to be reset
* @param eventLabelId the label of the timer event to send; 0 if no event should be sent
+ * @return the reset {@code timer} or {@code null} if the timer was deleted
*/
- void resetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
- doResetOrDeleteTimer(timer, eventLabelId);
+ Timer resetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
+ final Timer result = doResetOrDeleteTimer(timer, eventLabelId);
// Update the notification after updating the timer data.
updateNotification();
@@ -281,6 +282,8 @@
if (timer.isExpired()) {
updateHeadsUpNotification();
}
+
+ return result;
}
/**
@@ -361,6 +364,13 @@
}
/**
+ * @param uri the uri of the ringtone to play for all timers
+ */
+ void setTimerRingtoneUri(Uri uri) {
+ mSettingsModel.setTimerRingtoneUri(uri);
+ }
+
+ /**
* @return the title of the ringtone that is played for all timers
*/
String getTimerRingtoneTitle() {
@@ -385,6 +395,20 @@
return mTimerRingtoneTitle;
}
+ /**
+ * @return whether vibration is enabled for timers.
+ */
+ boolean getTimerVibrate() {
+ return mSettingsModel.getTimerVibrate();
+ }
+
+ /**
+ * @param enabled whether the
+ */
+ void setTimerVibrate(boolean enabled) {
+ mSettingsModel.setTimerVibrate(enabled);
+ }
+
private List<Timer> getMutableTimers() {
if (mTimers == null) {
mTimers = TimerDAO.getTimers(mContext);
@@ -500,19 +524,25 @@
*
* @param timer the timer to be reset
* @param eventLabelId the label of the timer event to send; 0 if no event should be sent
+ * @return the reset {@code timer} or {@code null} if the timer was deleted
*/
- private void doResetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
+ private Timer doResetOrDeleteTimer(Timer timer, @StringRes int eventLabelId) {
if (timer.isExpired() && timer.getDeleteAfterUse()) {
doRemoveTimer(timer);
if (eventLabelId != 0) {
Events.sendTimerEvent(R.string.action_delete, eventLabelId);
}
+ return null;
} else if (!timer.isReset()) {
- doUpdateTimer(timer.reset());
+ final Timer reset = timer.reset();
+ doUpdateTimer(reset);
if (eventLabelId != 0) {
Events.sendTimerEvent(R.string.action_reset, eventLabelId);
}
+ return reset;
}
+
+ return timer;
}
/**
@@ -859,8 +889,7 @@
private void schedulePendingIntent(long triggerTime, PendingIntent pi) {
if (Utils.isMOrLater()) {
- // Make sure the timer fires when the device is in doze mode. The timer is not
- // guaranteed to fire at the requested time. It may be delayed up to 15 minutes.
+ // Ensure the timer fires even if the device is dozing.
mAlarmManager.setExactAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP, triggerTime, pi);
} else {
mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, triggerTime, pi);
@@ -893,4 +922,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/settings/AlarmVolumePreference.java b/src/com/android/deskclock/settings/AlarmVolumePreference.java
new file mode 100644
index 0000000..b186769
--- /dev/null
+++ b/src/com/android/deskclock/settings/AlarmVolumePreference.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.settings;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+
+import com.android.deskclock.R;
+import com.android.deskclock.RingtonePreviewKlaxon;
+import com.android.deskclock.data.DataModel;
+
+public class AlarmVolumePreference extends Preference {
+
+ private static final long ALARM_PREVIEW_DURATION_MS = 2000;
+
+ private SeekBar mSeekbar;
+ private ImageView mAlarmIcon;
+ private boolean mPreviewPlaying;
+
+ public AlarmVolumePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ // Disable click feedback for this preference.
+ holder.itemView.setClickable(false);
+
+ final Context context = getContext();
+ final AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mSeekbar = (SeekBar) holder.findViewById(R.id.alarm_volume_slider);
+ mSeekbar.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM));
+ mSeekbar.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_ALARM));
+ mAlarmIcon = (ImageView) holder.findViewById(R.id.alarm_icon);
+ updateIcon();
+
+ final ContentObserver volumeObserver = new ContentObserver(mSeekbar.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // Volume was changed elsewhere, update our slider.
+ mSeekbar.setProgress(audioManager.getStreamVolume(
+ AudioManager.STREAM_ALARM));
+ }
+ };
+
+ mSeekbar.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ context.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI,
+ true, volumeObserver);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ context.getContentResolver().unregisterContentObserver(volumeObserver);
+ }
+ });
+
+
+ mSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+ audioManager.setStreamVolume(
+ AudioManager.STREAM_ALARM, seekBar.getProgress(), 0);
+ }
+ updateIcon();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ if (!mPreviewPlaying) {
+ RingtonePreviewKlaxon.start(
+ context, DataModel.getDataModel().getDefaultAlarmRingtoneUri());
+ mPreviewPlaying = true;
+
+ seekBar.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ RingtonePreviewKlaxon.stop(context);
+ mPreviewPlaying = false;
+ }
+ }, ALARM_PREVIEW_DURATION_MS);
+ }
+ }
+ });
+ }
+
+ private void updateIcon() {
+ mAlarmIcon.setImageResource(mSeekbar.getProgress() == 0 ?
+ R.drawable.ic_alarm_off_24dp : R.drawable.ic_alarm_small_24dp);
+ }
+}
diff --git a/src/com/android/deskclock/settings/CrescendoLengthDialog.java b/src/com/android/deskclock/settings/CrescendoLengthDialog.java
deleted file mode 100644
index 8b8b6f3..0000000
--- a/src/com/android/deskclock/settings/CrescendoLengthDialog.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package com.android.deskclock.settings;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Parcelable;
-import android.preference.DialogPreference;
-import android.support.annotation.NonNull;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.NumberPicker;
-import android.widget.TextView;
-
-import com.android.deskclock.NumberPickerCompat;
-import com.android.deskclock.R;
-
-/**
- * A dialog preference that shows a number picker for selecting crescendo length
- */
-public final class CrescendoLengthDialog extends DialogPreference {
-
- private static final String DEFAULT_CRESCENDO_TIME = "0";
- private static final int CRESCENDO_TIME_STEP = 5;
-
- private NumberPickerCompat mNumberPickerView;
- private TextView mNumberPickerSecondsView;
- private int mCrescendoSeconds;
-
- public CrescendoLengthDialog(Context context, AttributeSet attrs) {
- super(context, attrs);
- setDialogLayoutResource(R.layout.crescendo_length_picker);
- setTitle(R.string.crescendo_duration_title);
- }
-
- @Override
- protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
- super.onPrepareDialogBuilder(builder);
- builder.setTitle(getContext().getString(R.string.crescendo_duration_title))
- .setCancelable(true);
- }
-
- @Override
- protected void onBindDialogView(@NonNull View view) {
- super.onBindDialogView(view);
-
- final String[] displayedValues = new String[13];
- displayedValues[0] = getContext().getString(R.string.no_crescendo_duration);
- for (int i = 1; i < displayedValues.length; i++) {
- displayedValues[i] = String.valueOf(i * CRESCENDO_TIME_STEP);
- }
-
- mNumberPickerSecondsView = (TextView) view.findViewById(R.id.title);
- mNumberPickerSecondsView.setText(getContext().getString(R.string.crescendo_picker_label));
- mNumberPickerView = (NumberPickerCompat) view.findViewById(R.id.seconds_picker);
- mNumberPickerView.setDisplayedValues(displayedValues);
- mNumberPickerView.setMinValue(0);
- mNumberPickerView.setMaxValue(displayedValues.length - 1);
- mNumberPickerView.setValue(mCrescendoSeconds / CRESCENDO_TIME_STEP);
- updateUnits();
-
- mNumberPickerView.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
- @Override
- public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
- updateUnits();
- }
- });
- mNumberPickerView.setOnAnnounceValueChangedListener(
- new NumberPickerCompat.OnAnnounceValueChangedListener() {
- @Override
- public void onAnnounceValueChanged(NumberPicker picker, int value,
- String displayedValue) {
- final String announceString;
- if (value == 0) {
- announceString = getContext().getString(R.string.no_crescendo_duration);
- } else {
- announceString = getContext().getString(
- R.string.crescendo_duration, displayedValue);
- }
- picker.announceForAccessibility(announceString);
- }
- });
- }
-
- @Override
- protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
- String val;
- if (restorePersistedValue) {
- val = getPersistedString(DEFAULT_CRESCENDO_TIME);
- if (val != null) {
- mCrescendoSeconds = Integer.parseInt(val);
- }
- } else {
- val = (String) defaultValue;
- if (val != null) {
- mCrescendoSeconds = Integer.parseInt(val);
- }
- persistString(val);
- }
- }
-
- @Override
- protected Object onGetDefaultValue(TypedArray a, int index) {
- return a.getString(index);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- // Restore the value to the NumberPicker.
- super.onRestoreInstanceState(state);
-
- // Update the unit display in response to the new value.
- updateUnits();
- }
-
- private void updateUnits() {
- if (mNumberPickerView != null) {
- final int value = mNumberPickerView.getValue();
- final int visibility = value == 0 ? View.INVISIBLE : View.VISIBLE;
- mNumberPickerSecondsView.setVisibility(visibility);
- }
- }
-
- @Override
- protected void onDialogClosed(boolean positiveResult) {
- if (positiveResult) {
- mNumberPickerView.clearFocus();
- mCrescendoSeconds = mNumberPickerView.getValue() * CRESCENDO_TIME_STEP;
- persistString(Integer.toString(mCrescendoSeconds));
- setSummary();
- }
- }
-
- public void setSummary() {
- if (mCrescendoSeconds == 0) {
- setSummary(getContext().getString(R.string.no_crescendo_duration));
- } else {
- setSummary(getContext().getString(R.string.crescendo_duration, mCrescendoSeconds));
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/deskclock/settings/CrescendoLengthDialogFragment.java b/src/com/android/deskclock/settings/CrescendoLengthDialogFragment.java
new file mode 100644
index 0000000..5cff800
--- /dev/null
+++ b/src/com/android/deskclock/settings/CrescendoLengthDialogFragment.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.settings;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceDialogFragment;
+import android.support.v7.preference.Preference;
+import android.view.View;
+import android.widget.NumberPicker;
+import android.widget.TextView;
+
+import com.android.deskclock.NumberPickerCompat;
+import com.android.deskclock.R;
+
+public class CrescendoLengthDialogFragment extends PreferenceDialogFragment {
+
+ private static final int CRESCENDO_TIME_STEP = 5;
+
+ private NumberPickerCompat mNumberPickerView;
+
+ public static DialogFragment newInstance(Preference preference) {
+ final CrescendoLengthDialogFragment fragment = new CrescendoLengthDialogFragment();
+ final Bundle bundle = new Bundle();
+ bundle.putString(ARG_KEY, preference.getKey());
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getPreference().setDialogLayoutResource(R.layout.crescendo_length_picker);
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ final CrescendoLengthDialogPreference preference =
+ (CrescendoLengthDialogPreference) getPreference();
+ final int crescendoSeconds = preference.getPersistedCrescendoLength();
+
+ final TextView unitView = (TextView) view.findViewById(R.id.title);
+ unitView.setText(R.string.crescendo_picker_label);
+ updateUnits(unitView, crescendoSeconds);
+
+ final String[] displayedValues = new String[13];
+ displayedValues[0] = getString(R.string.no_crescendo_duration);
+ for (int i = 1; i < displayedValues.length; i++) {
+ displayedValues[i] = String.valueOf(i * CRESCENDO_TIME_STEP);
+ }
+
+ mNumberPickerView = (NumberPickerCompat) view.findViewById(R.id.seconds_picker);
+ mNumberPickerView.setDisplayedValues(displayedValues);
+ mNumberPickerView.setMinValue(0);
+ mNumberPickerView.setMaxValue(displayedValues.length - 1);
+ mNumberPickerView.setValue(crescendoSeconds / CRESCENDO_TIME_STEP);
+
+ mNumberPickerView.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
+ @Override
+ public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+ updateUnits(unitView, newVal);
+ }
+ });
+ mNumberPickerView.setOnAnnounceValueChangedListener(
+ new NumberPickerCompat.OnAnnounceValueChangedListener() {
+ @Override
+ public void onAnnounceValueChanged(NumberPicker picker, int value,
+ String displayedValue) {
+ final String announceString;
+ if (value == 0) {
+ announceString = getString(R.string.no_crescendo_duration);
+ } else {
+ announceString = getString(R.string.crescendo_duration, displayedValue);
+ }
+ picker.announceForAccessibility(announceString);
+ }
+ });
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ final CrescendoLengthDialogPreference preference =
+ (CrescendoLengthDialogPreference) getPreference();
+ preference.persistCrescendoLength(mNumberPickerView.getValue() * CRESCENDO_TIME_STEP);
+ preference.updateSummary();
+ }
+ }
+
+ private void updateUnits(TextView unitView, int crescendoSeconds) {
+ final int visibility = crescendoSeconds == 0 ? View.INVISIBLE : View.VISIBLE;
+ unitView.setVisibility(visibility);
+ }
+}
diff --git a/src/com/android/deskclock/settings/CrescendoLengthDialogPreference.java b/src/com/android/deskclock/settings/CrescendoLengthDialogPreference.java
new file mode 100644
index 0000000..6fc6d38
--- /dev/null
+++ b/src/com/android/deskclock/settings/CrescendoLengthDialogPreference.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.settings;
+
+import android.content.Context;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+
+import com.android.deskclock.R;
+
+public class CrescendoLengthDialogPreference extends DialogPreference {
+
+ private static final String DEFAULT_CRESCENDO_TIME = "0";
+
+ public CrescendoLengthDialogPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public int getPersistedCrescendoLength() {
+ return Integer.parseInt(getPersistedString(DEFAULT_CRESCENDO_TIME));
+ }
+
+ public void persistCrescendoLength(int crescendoSeconds) {
+ persistString(Integer.toString(crescendoSeconds));
+ }
+
+ public void updateSummary() {
+ final int crescendoSeconds = getPersistedCrescendoLength();
+ if (crescendoSeconds == 0) {
+ setSummary(getContext().getString(R.string.no_crescendo_duration));
+ } else {
+ setSummary(getContext().getString(R.string.crescendo_duration, crescendoSeconds));
+ }
+ }
+}
diff --git a/src/com/android/deskclock/settings/SettingsActivity.java b/src/com/android/deskclock/settings/SettingsActivity.java
index c5d2284..52294b3 100644
--- a/src/com/android/deskclock/settings/SettingsActivity.java
+++ b/src/com/android/deskclock/settings/SettingsActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,17 +17,17 @@
package com.android.deskclock.settings;
import android.app.Activity;
-import android.content.Context;
+import android.app.DialogFragment;
+import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.res.Resources;
-import android.media.AudioManager;
+import android.net.Uri;
import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.preference.RingtonePreference;
-import android.preference.SwitchPreference;
import android.provider.Settings;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
import android.text.format.DateUtils;
import android.view.Menu;
import android.view.MenuItem;
@@ -35,6 +35,7 @@
import com.android.deskclock.BaseActivity;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
+import com.android.deskclock.RingtonePickerDialogFragment;
import com.android.deskclock.Utils;
import com.android.deskclock.actionbarmenu.ActionBarMenuManager;
import com.android.deskclock.actionbarmenu.MenuItemControllerFactory;
@@ -44,19 +45,19 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Locale;
import java.util.TimeZone;
/**
* Settings for the Alarm Clock.
*/
-public final class SettingsActivity extends BaseActivity {
+public final class SettingsActivity extends BaseActivity
+ implements RingtonePickerDialogFragment.RingtoneSelectionListener {
public static final String KEY_ALARM_SNOOZE = "snooze_duration";
- public static final String KEY_ALARM_VOLUME = "volume_setting";
public static final String KEY_ALARM_CRESCENDO = "alarm_crescendo_duration";
public static final String KEY_TIMER_CRESCENDO = "timer_crescendo_duration";
public static final String KEY_TIMER_RINGTONE = "timer_ringtone";
+ public static final String KEY_TIMER_VIBRATE = "timer_vibrate";
public static final String KEY_AUTO_SILENCE = "auto_silence";
public static final String KEY_CLOCK_STYLE = "clock_style";
public static final String KEY_HOME_TZ = "home_time_zone";
@@ -71,16 +72,26 @@
public static final String VOLUME_BEHAVIOR_SNOOZE = "1";
public static final String VOLUME_BEHAVIOR_DISMISS = "2";
- private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager(this);
+ public static final String PREFS_FRAGMENT_TAG = "prefs_fragment";
+ public static final String PREFERENCE_DIALOG_FRAGMENT_TAG = "preference_dialog";
+
+ private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setVolumeControlStream(AudioManager.STREAM_ALARM);
setContentView(R.layout.settings);
mActionBarMenuManager.addMenuItemController(new NavUpMenuItemController(this))
.addMenuItemController(MenuItemControllerFactory.getInstance()
.buildMenuItemControllers(this));
+
+ // Create the prefs fragment in code to ensure it's created before PreferenceDialogFragment
+ if (savedInstanceState == null) {
+ final FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(R.id.main, new PrefsFragment(), PREFS_FRAGMENT_TAG);
+ ft.addToBackStack(null);
+ ft.commit();
+ }
}
@Override
@@ -103,12 +114,23 @@
return super.onOptionsItemSelected(item);
}
+ /**
+ * Called by the RingtonePickerDialogFragment class after the dialog is finished.
+ */
+ @Override
+ public void onRingtoneSelected(Uri ringtoneUri, String fragmentTag) {
+ final PrefsFragment fragment =
+ (PrefsFragment) getFragmentManager().findFragmentById(R.id.main);
+ final Preference preference = fragment.findPreference(KEY_TIMER_RINGTONE);
+ DataModel.getDataModel().setTimerRingtoneUri(ringtoneUri);
+ preference.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
+ }
+
public static class PrefsFragment extends PreferenceFragment
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ @Override
+ public void onCreatePreferences(Bundle bundle, String rootKey) {
addPreferencesFromResource(R.xml.settings);
loadTimeZoneList();
}
@@ -130,6 +152,22 @@
}
@Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+ final String key = preference.getKey();
+ switch (key) {
+ case KEY_ALARM_SNOOZE:
+ showDialog(SnoozeLengthDialogFragment.newInstance(preference));
+ break;
+ case KEY_ALARM_CRESCENDO:
+ case KEY_TIMER_CRESCENDO:
+ showDialog(CrescendoLengthDialogFragment.newInstance(preference));
+ break;
+ default:
+ super.onDisplayPreferenceDialog(preference);
+ }
+ }
+
+ @Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
final int idx;
switch (pref.getKey()) {
@@ -159,15 +197,15 @@
volumeButtonsPref.setSummary(volumeButtonsPref.getEntries()[index]);
break;
case KEY_WEEK_START:
- final ListPreference weekStartPref = (ListPreference)
- findPreference(KEY_WEEK_START);
+ final ListPreference weekStartPref =
+ (ListPreference) findPreference(KEY_WEEK_START);
idx = weekStartPref.findIndexOfValue((String) newValue);
weekStartPref.setSummary(weekStartPref.getEntries()[idx]);
break;
- case KEY_TIMER_RINGTONE:
- final RingtonePreference timerRingtonePref = (RingtonePreference)
- findPreference(KEY_TIMER_RINGTONE);
- timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
+ case KEY_TIMER_VIBRATE:
+ final SwitchPreference timerVibratePref =
+ (SwitchPreference) findPreference(KEY_TIMER_VIBRATE);
+ DataModel.getDataModel().setTimerVibrate(timerVibratePref.isChecked());
break;
}
// Set result so DeskClock knows to refresh itself
@@ -188,12 +226,14 @@
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
return true;
- case KEY_ALARM_VOLUME:
- final AudioManager audioManager =
- (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
- audioManager.adjustStreamVolume(AudioManager.STREAM_ALARM,
- AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
- return true;
+ case KEY_TIMER_RINGTONE:
+ final String dialogTitle = getString(R.string.timer_ringtone_title);
+ final String defaultTitle = getString(R.string.default_timer_ringtone_title);
+ final Uri currentUri = DataModel.getDataModel().getTimerRingtoneUri();
+ final Uri defaultUri = DataModel.getDataModel().getDefaultTimerRingtoneUri();
+ final DialogFragment newFragment = RingtonePickerDialogFragment
+ .newInstance(dialogTitle, defaultTitle, defaultUri, currentUri, null);
+ showDialog(newFragment);
default:
return false;
}
@@ -271,20 +311,9 @@
volumeButtonsPref.setSummary(volumeButtonsPref.getEntry());
volumeButtonsPref.setOnPreferenceChangeListener(this);
- final Preference volumePref = findPreference(KEY_ALARM_VOLUME);
- volumePref.setOnPreferenceClickListener(this);
-
- final SnoozeLengthDialog snoozePref =
- (SnoozeLengthDialog) findPreference(KEY_ALARM_SNOOZE);
- snoozePref.setSummary();
-
- final CrescendoLengthDialog alarmCrescendoPref =
- (CrescendoLengthDialog) findPreference(KEY_ALARM_CRESCENDO);
- alarmCrescendoPref.setSummary();
-
- final CrescendoLengthDialog timerCrescendoPref =
- (CrescendoLengthDialog) findPreference(KEY_TIMER_CRESCENDO);
- timerCrescendoPref.setSummary();
+ ((SnoozeLengthDialogPreference) findPreference(KEY_ALARM_SNOOZE)).updateSummary();
+ ((CrescendoLengthDialogPreference) findPreference(KEY_ALARM_CRESCENDO)).updateSummary();
+ ((CrescendoLengthDialogPreference) findPreference(KEY_TIMER_CRESCENDO)).updateSummary();
final Preference dateAndTimeSetting = findPreference(KEY_DATE_TIME);
dateAndTimeSetting.setOnPreferenceClickListener(this);
@@ -298,10 +327,9 @@
weekStartPref.setSummary(weekStartPref.getEntries()[idx]);
weekStartPref.setOnPreferenceChangeListener(this);
- final RingtonePreference timerRingtonePref =
- (RingtonePreference) findPreference(KEY_TIMER_RINGTONE);
+ final Preference timerRingtonePref = findPreference(KEY_TIMER_RINGTONE);
+ timerRingtonePref.setOnPreferenceClickListener(this);
timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
- timerRingtonePref.setOnPreferenceChangeListener(this);
}
private void updateAutoSnoozeSummary(ListPreference listPref, String delay) {
@@ -314,6 +342,11 @@
}
}
+ private void showDialog(DialogFragment fragment) {
+ fragment.setTargetFragment(this, 0);
+ fragment.show(getFragmentManager(), PREFERENCE_DIALOG_FRAGMENT_TAG);
+ }
+
private static class TimeZoneRow implements Comparable<TimeZoneRow> {
private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false;
diff --git a/src/com/android/deskclock/settings/SnoozeLengthDialog.java b/src/com/android/deskclock/settings/SnoozeLengthDialog.java
deleted file mode 100644
index a9a3aae..0000000
--- a/src/com/android/deskclock/settings/SnoozeLengthDialog.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.deskclock.settings;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Parcelable;
-import android.preference.DialogPreference;
-import android.support.annotation.NonNull;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.NumberPicker;
-import android.widget.TextView;
-
-import com.android.deskclock.NumberPickerCompat;
-import com.android.deskclock.R;
-import com.android.deskclock.Utils;
-
-/**
- * A dialog preference that shows a number picker for selecting snooze length
- */
-public final class SnoozeLengthDialog extends DialogPreference {
-
- private static final String DEFAULT_SNOOZE_TIME = "10";
-
- private NumberPickerCompat mNumberPickerView;
- private TextView mNumberPickerMinutesView;
- private final Context mContext;
- private int mSnoozeMinutes;
-
- public SnoozeLengthDialog(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- setDialogLayoutResource(R.layout.snooze_length_picker);
- setTitle(R.string.snooze_duration_title);
- }
-
- @Override
- protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
- super.onPrepareDialogBuilder(builder);
- builder.setTitle(getContext().getString(R.string.snooze_duration_title))
- .setCancelable(true);
- }
-
- @Override
- protected void onBindDialogView(@NonNull View view) {
- super.onBindDialogView(view);
- mNumberPickerMinutesView = (TextView) view.findViewById(R.id.title);
- mNumberPickerView = (NumberPickerCompat) view.findViewById(R.id.minutes_picker);
- mNumberPickerView.setMinValue(1);
- mNumberPickerView.setMaxValue(30);
- mNumberPickerView.setValue(mSnoozeMinutes);
- updateUnits();
-
- mNumberPickerView.setOnAnnounceValueChangedListener(
- new NumberPickerCompat.OnAnnounceValueChangedListener() {
- @Override
- public void onAnnounceValueChanged(NumberPicker picker, int value,
- String displayedValue) {
- final String announceString = Utils.getNumberFormattedQuantityString(
- mContext, R.plurals.snooze_duration, value);
- picker.announceForAccessibility(announceString);
- }
- });
- }
-
- @Override
- protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
- String val;
- if (restorePersistedValue) {
- val = getPersistedString(DEFAULT_SNOOZE_TIME);
- if (val != null) {
- mSnoozeMinutes = Integer.parseInt(val);
- }
- } else {
- val = (String) defaultValue;
- if (val != null) {
- mSnoozeMinutes = Integer.parseInt(val);
- }
- persistString(val);
- }
- }
-
- @Override
- protected Object onGetDefaultValue(TypedArray a, int index) {
- return a.getString(index);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- // Restore the value to the NumberPicker.
- super.onRestoreInstanceState(state);
-
- // Update the unit display in response to the new value.
- updateUnits();
- }
-
- private void updateUnits() {
- if (mNumberPickerView != null) {
- final Resources res = mContext.getResources();
- final int value = mNumberPickerView.getValue();
- final CharSequence units = res.getQuantityText(R.plurals.snooze_picker_label, value);
- mNumberPickerMinutesView.setText(units);
- }
- }
-
- @Override
- protected void onDialogClosed(boolean positiveResult) {
- if (positiveResult) {
- mNumberPickerView.clearFocus();
- mSnoozeMinutes = mNumberPickerView.getValue();
- persistString(Integer.toString(mSnoozeMinutes));
- setSummary();
- }
- }
-
- public void setSummary() {
- setSummary(Utils.getNumberFormattedQuantityString(mContext, R.plurals.snooze_duration,
- mSnoozeMinutes));
- }
-}
\ No newline at end of file
diff --git a/src/com/android/deskclock/settings/SnoozeLengthDialogFragment.java b/src/com/android/deskclock/settings/SnoozeLengthDialogFragment.java
new file mode 100644
index 0000000..8e562c0
--- /dev/null
+++ b/src/com/android/deskclock/settings/SnoozeLengthDialogFragment.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.settings;
+
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceDialogFragment;
+import android.support.v7.preference.Preference;
+import android.view.View;
+import android.widget.NumberPicker;
+import android.widget.TextView;
+
+import com.android.deskclock.NumberPickerCompat;
+import com.android.deskclock.R;
+import com.android.deskclock.Utils;
+
+public class SnoozeLengthDialogFragment extends PreferenceDialogFragment {
+
+ private NumberPickerCompat mNumberPickerView;
+
+ public static DialogFragment newInstance(Preference preference) {
+ SnoozeLengthDialogFragment fragment = new SnoozeLengthDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putString(ARG_KEY, preference.getKey());
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getPreference().setDialogLayoutResource(R.layout.snooze_length_picker);
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ final SnoozeLengthDialogPreference preference =
+ (SnoozeLengthDialogPreference) getPreference();
+ final int snoozeMinutes = preference.getPersistedSnoozeLength();
+
+ final CharSequence units =
+ getResources().getQuantityText(R.plurals.snooze_picker_label, snoozeMinutes);
+ final TextView unitView = (TextView) view.findViewById(R.id.title);
+ unitView.setText(units);
+
+ mNumberPickerView = (NumberPickerCompat) view.findViewById(R.id.minutes_picker);
+ mNumberPickerView.setMinValue(1);
+ mNumberPickerView.setMaxValue(30);
+ mNumberPickerView.setValue(snoozeMinutes);
+
+ mNumberPickerView.setOnAnnounceValueChangedListener(
+ new NumberPickerCompat.OnAnnounceValueChangedListener() {
+ @Override
+ public void onAnnounceValueChanged(NumberPicker picker, int value,
+ String displayedValue) {
+ final String announceString = Utils.getNumberFormattedQuantityString(
+ getActivity(), R.plurals.snooze_duration, value);
+ picker.announceForAccessibility(announceString);
+ }
+ });
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ if (positiveResult) {
+ final SnoozeLengthDialogPreference preference =
+ (SnoozeLengthDialogPreference) getPreference();
+ preference.persistSnoozeLength(mNumberPickerView.getValue());
+ preference.updateSummary();
+ }
+ }
+}
diff --git a/src/com/android/deskclock/settings/SnoozeLengthDialogPreference.java b/src/com/android/deskclock/settings/SnoozeLengthDialogPreference.java
new file mode 100644
index 0000000..0de0fcb
--- /dev/null
+++ b/src/com/android/deskclock/settings/SnoozeLengthDialogPreference.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.settings;
+
+import android.content.Context;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+
+import com.android.deskclock.R;
+import com.android.deskclock.Utils;
+
+public class SnoozeLengthDialogPreference extends DialogPreference {
+
+ private static final String DEFAULT_SNOOZE_TIME = "10";
+
+ public SnoozeLengthDialogPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public int getPersistedSnoozeLength() {
+ return Integer.parseInt(getPersistedString(DEFAULT_SNOOZE_TIME));
+ }
+
+ public void persistSnoozeLength(int snoozeMinutes) {
+ persistString(Integer.toString(snoozeMinutes));
+ }
+
+ public void updateSummary() {
+ final int value = getPersistedSnoozeLength();
+ final CharSequence summary = Utils.getNumberFormattedQuantityString(
+ getContext(), R.plurals.snooze_duration, value);
+ setSummary(summary);
+ }
+}
diff --git a/src/com/android/deskclock/settings/TimerRingtonePreference.java b/src/com/android/deskclock/settings/TimerRingtonePreference.java
deleted file mode 100644
index 7a30d92..0000000
--- a/src/com/android/deskclock/settings/TimerRingtonePreference.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.deskclock.settings;
-
-import android.content.Context;
-import android.content.Intent;
-import android.media.RingtoneManager;
-import android.preference.RingtonePreference;
-import android.support.annotation.NonNull;
-import android.util.AttributeSet;
-
-import com.android.deskclock.data.DataModel;
-
-/**
- * A custom RingtonePreference that presents the application's default timer ringtone as the value
- * behind the default selection.
- */
-public final class TimerRingtonePreference extends RingtonePreference {
-
- public TimerRingtonePreference(Context context) {
- super(context);
- }
-
- public TimerRingtonePreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public TimerRingtonePreference(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public TimerRingtonePreference(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- @Override
- protected void onPrepareRingtonePickerIntent(@NonNull Intent ringtonePickerIntent) {
- super.onPrepareRingtonePickerIntent(ringtonePickerIntent);
-
- // Replace the default ringtone uri with the beeping ringtone for timers.
- ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI,
- DataModel.getDataModel().getDefaultTimerRingtoneUri());
- }
-}
\ No newline at end of file
diff --git a/src/com/android/deskclock/stopwatch/StopwatchCircleView.java b/src/com/android/deskclock/stopwatch/StopwatchCircleView.java
index bd2e207..f386598 100644
--- a/src/com/android/deskclock/stopwatch/StopwatchCircleView.java
+++ b/src/com/android/deskclock/stopwatch/StopwatchCircleView.java
@@ -80,7 +80,7 @@
mMarkerStrokeSize = resources.getDimension(R.dimen.circletimer_marker_size);
mRadiusOffset = Utils.calculateRadiusOffset(mStrokeSize, dotDiameter, mMarkerStrokeSize);
- mRemainderColor = resources.getColor(R.color.clock_white);
+ mRemainderColor = Color.WHITE;
mCompletedColor = Utils.obtainStyledColor(context, R.attr.colorAccent, Color.RED);
mPaint.setAntiAlias(true);
@@ -173,4 +173,4 @@
private List<Lap> getLaps() {
return DataModel.getDataModel().getLaps();
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/stopwatch/StopwatchFragment.java b/src/com/android/deskclock/stopwatch/StopwatchFragment.java
index 28c8997..15f5891 100644
--- a/src/com/android/deskclock/stopwatch/StopwatchFragment.java
+++ b/src/com/android/deskclock/stopwatch/StopwatchFragment.java
@@ -16,39 +16,46 @@
package com.android.deskclock.stopwatch;
+import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.PowerManager;
import android.os.SystemClock;
+import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.SimpleItemAnimator;
import android.transition.AutoTransition;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageButton;
+import android.widget.ImageView;
-import com.android.deskclock.DeskClock;
import com.android.deskclock.DeskClockFragment;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
+import com.android.deskclock.Utils;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.data.Lap;
import com.android.deskclock.data.Stopwatch;
import com.android.deskclock.events.Events;
import com.android.deskclock.timer.CountingTimerView;
+import com.android.deskclock.uidata.TabListener;
+import com.android.deskclock.uidata.UiDataModel;
+import com.android.deskclock.uidata.UiDataModel.Tab;
import static android.content.Context.ACCESSIBILITY_SERVICE;
-import static android.content.Context.POWER_SERVICE;
-import static android.os.PowerManager.ON_AFTER_RELEASE;
-import static android.os.PowerManager.SCREEN_BRIGHT_WAKE_LOCK;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_AND_BUTTONS_IMMEDIATE;
+import static com.android.deskclock.uidata.UiDataModel.Tab.STOPWATCH;
/**
* Fragment that shows the stopwatch and recorded laps.
@@ -57,35 +64,57 @@
private static final String TAG = "StopwatchFragment";
- /** Scheduled to update the stopwatch time and current lap time while stopwatch is running. */
+ /**
+ * Keep the screen on when this tab is selected.
+ */
+ private final TabListener mTabWatcher = new TabWatcher();
+
+ /**
+ * Scheduled to update the stopwatch time and current lap time while stopwatch is running.
+ */
private final Runnable mTimeUpdateRunnable = new TimeUpdateRunnable();
- /** Used to determine when talk back is on in order to lower the time update rate. */
+ /**
+ * Used to determine when talk back is on in order to lower the time update rate.
+ */
private AccessibilityManager mAccessibilityManager;
- /** {@code true} while the {@link #mLapsList} is transitioning between shown and hidden. */
+ /**
+ * {@code true} while the {@link #mLapsList} is transitioning between shown and hidden.
+ */
private boolean mLapsListIsTransitioning;
- /** The data source for {@link #mLapsList}. */
+ /**
+ * The data source for {@link #mLapsList}.
+ */
private LapsAdapter mLapsAdapter;
- /** The layout manager for the {@link #mLapsAdapter}. */
+ /**
+ * The layout manager for the {@link #mLapsAdapter}.
+ */
private LinearLayoutManager mLapsLayoutManager;
- /** Draws the reference lap while the stopwatch is running. */
+ /**
+ * Draws the reference lap while the stopwatch is running.
+ */
private StopwatchCircleView mTime;
- /** Displays the recorded lap times. */
+ /**
+ * Displays the recorded lap times.
+ */
private RecyclerView mLapsList;
- /** Displays the current stopwatch time. */
+ /**
+ * Displays the current stopwatch time.
+ */
private CountingTimerView mTimeText;
- /** Held while the stopwatch is running and this fragment is forward to keep the screen on. */
- private PowerManager.WakeLock mWakeLock;
-
- /** The public no-arg constructor required by all fragments. */
- public StopwatchFragment() {}
+ /**
+ * The public no-arg constructor required by all fragments.
+ */
+ public StopwatchFragment() {
+ super(STOPWATCH);
+ }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
@@ -95,7 +124,7 @@
final View v = inflater.inflate(R.layout.stopwatch_fragment, container, false);
mTime = (StopwatchCircleView) v.findViewById(R.id.stopwatch_time);
mLapsList = (RecyclerView) v.findViewById(R.id.laps_list);
- mLapsList.getItemAnimator().setSupportsChangeAnimations(false);
+ ((SimpleItemAnimator) mLapsList.getItemAnimator()).setSupportsChangeAnimations(false);
mLapsList.setLayoutManager(mLapsLayoutManager);
mLapsList.setAdapter(mLapsAdapter);
@@ -122,10 +151,6 @@
// Conservatively assume the data in the adapter has changed while the fragment was paused.
mLapsAdapter.notifyDataSetChanged();
- // Update the state of the buttons.
- setFabAppearance();
- setLeftRightButtonAppearance();
-
// Draw the current stopwatch and lap times.
updateTime();
@@ -145,7 +170,7 @@
showOrHideLaps(false);
// Start watching for page changes away from this fragment.
- getDeskClock().registerPageChangedListener(this);
+ UiDataModel.getUiDataModel().addTabListener(mTabWatcher);
// View is hidden in onPause, make sure it is visible now.
final View view = getView();
@@ -171,28 +196,19 @@
mTimeText.blinkTimeStr(false);
// Stop watching for page changes away from this fragment.
- getDeskClock().unregisterPageChangedListener(this);
+ UiDataModel.getUiDataModel().removeTabListener(mTabWatcher);
// Release the wake lock if it is currently held.
releaseWakeLock();
}
@Override
- public void onPageChanged(int page) {
- if (page == DeskClock.STOPWATCH_TAB_INDEX && getStopwatch().isRunning()) {
- acquireWakeLock();
- } else {
- releaseWakeLock();
- }
- }
-
- @Override
- public void onFabClick(View view) {
+ public void onFabClick(@NonNull ImageView fab) {
toggleStopwatchState();
}
@Override
- public void onLeftButtonClick(View view) {
+ public void onLeftButtonClick(@NonNull ImageButton left) {
switch (getStopwatch().getState()) {
case RUNNING:
doAddLap();
@@ -204,55 +220,46 @@
}
@Override
- public void onRightButtonClick(View view) {
+ public void onRightButtonClick(@NonNull ImageButton right) {
doShare();
}
@Override
- public void setFabAppearance() {
- if (mFab == null || getSelectedTab() != DeskClock.STOPWATCH_TAB_INDEX) {
- return;
- }
-
+ public void onUpdateFab(@NonNull ImageView fab) {
if (getStopwatch().isRunning()) {
- mFab.setImageResource(R.drawable.ic_pause_white_24dp);
- mFab.setContentDescription(getString(R.string.sw_pause_button));
+ fab.setImageResource(R.drawable.ic_pause_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.sw_pause_button));
} else {
- mFab.setImageResource(R.drawable.ic_start_white_24dp);
- mFab.setContentDescription(getString(R.string.sw_start_button));
+ fab.setImageResource(R.drawable.ic_start_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.sw_start_button));
}
- mFab.setVisibility(VISIBLE);
+ fab.setVisibility(VISIBLE);
}
@Override
- public void setLeftRightButtonAppearance() {
- if (mLeftButton == null || mRightButton == null ||
- getSelectedTab() != DeskClock.STOPWATCH_TAB_INDEX) {
- return;
- }
-
- mRightButton.setImageResource(R.drawable.ic_share);
- mRightButton.setContentDescription(getString(R.string.sw_share_button));
+ public void onUpdateFabButtons(@NonNull ImageButton left, @NonNull ImageButton right) {
+ right.setImageResource(R.drawable.ic_share);
+ right.setContentDescription(right.getResources().getString(R.string.sw_share_button));
switch (getStopwatch().getState()) {
case RESET:
- mLeftButton.setEnabled(false);
- mLeftButton.setVisibility(INVISIBLE);
- mRightButton.setVisibility(INVISIBLE);
+ left.setEnabled(false);
+ left.setVisibility(INVISIBLE);
+ right.setVisibility(INVISIBLE);
break;
case RUNNING:
- mLeftButton.setImageResource(R.drawable.ic_lap);
- mLeftButton.setContentDescription(getString(R.string.sw_lap_button));
- mLeftButton.setEnabled(canRecordMoreLaps());
- mLeftButton.setVisibility(canRecordMoreLaps() ? VISIBLE : INVISIBLE);
- mRightButton.setVisibility(INVISIBLE);
+ left.setImageResource(R.drawable.ic_lap);
+ left.setContentDescription(left.getResources().getString(R.string.sw_lap_button));
+ left.setEnabled(canRecordMoreLaps());
+ left.setVisibility(canRecordMoreLaps() ? VISIBLE : INVISIBLE);
+ right.setVisibility(INVISIBLE);
break;
case PAUSED:
- mLeftButton.setEnabled(true);
- mLeftButton.setImageResource(R.drawable.ic_reset);
- mLeftButton.setContentDescription(getString(R.string.sw_reset_button));
- mLeftButton.setVisibility(VISIBLE);
- mRightButton.setVisibility(VISIBLE);
+ left.setEnabled(true);
+ left.setImageResource(R.drawable.ic_reset);
+ left.setContentDescription(left.getResources().getString(R.string.sw_reset_button));
+ left.setVisibility(VISIBLE);
+ right.setVisibility(VISIBLE);
break;
}
}
@@ -272,8 +279,7 @@
mTimeText.blinkTimeStr(false);
// Update button states.
- setFabAppearance();
- setLeftRightButtonAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
// Acquire the wake lock.
acquireWakeLock();
@@ -296,8 +302,7 @@
mTimeText.blinkTimeStr(true);
// Update button states.
- setFabAppearance();
- setLeftRightButtonAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
// Release the wake lock.
releaseWakeLock();
@@ -321,8 +326,7 @@
mTimeText.blinkTimeStr(false);
// Update button states.
- setFabAppearance();
- setLeftRightButtonAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
// Release the wake lock.
releaseWakeLock();
@@ -333,11 +337,14 @@
*/
private void doShare() {
final String[] subjects = getResources().getStringArray(R.array.sw_share_strings);
- final String subject = subjects[(int)(Math.random() * subjects.length)];
+ final String subject = subjects[(int) (Math.random() * subjects.length)];
final String text = mLapsAdapter.getShareText();
+ @SuppressLint("InlinedApi")
+ @SuppressWarnings("deprecation")
final Intent shareIntent = new Intent(Intent.ACTION_SEND)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+ .addFlags(Utils.isLOrLater() ? Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+ : Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
.putExtra(Intent.EXTRA_SUBJECT, subject)
.putExtra(Intent.EXTRA_TEXT, text)
.setType("text/plain");
@@ -365,7 +372,7 @@
}
// Update button states.
- setLeftRightButtonAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
if (lap.getLapNumber() == 1) {
// Child views from prior lap sets hang around and blit to the screen when adding the
@@ -425,18 +432,15 @@
}
private void acquireWakeLock() {
- if (mWakeLock == null) {
- final PowerManager pm = (PowerManager) getActivity().getSystemService(POWER_SERVICE);
- mWakeLock = pm.newWakeLock(SCREEN_BRIGHT_WAKE_LOCK | ON_AFTER_RELEASE, TAG);
- mWakeLock.setReferenceCounted(false);
+ if (isTabSelected()) {
+ getActivity().getWindow()
+ .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
- mWakeLock.acquire();
}
private void releaseWakeLock() {
- if (mWakeLock != null && mWakeLock.isHeld()) {
- mWakeLock.release();
- }
+ getActivity().getWindow()
+ .clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
/**
@@ -529,4 +533,19 @@
toggleStopwatchState();
}
}
-}
\ No newline at end of file
+
+ /**
+ * Acquire the wake lock if the stopwatch tab is selected and the stopwatch is running; release
+ * it otherwise.
+ */
+ private final class TabWatcher implements TabListener {
+ @Override
+ public void selectedTabChanged(Tab oldSelectedTab, Tab newSelectedTab) {
+ if (isTabSelected() && getStopwatch().isRunning()) {
+ acquireWakeLock();
+ } else {
+ releaseWakeLock();
+ }
+ }
+ }
+}
diff --git a/src/com/android/deskclock/timer/CountingTimerView.java b/src/com/android/deskclock/timer/CountingTimerView.java
index bb5778c..c221e6a 100644
--- a/src/com/android/deskclock/timer/CountingTimerView.java
+++ b/src/com/android/deskclock/timer/CountingTimerView.java
@@ -264,7 +264,7 @@
mAccessibilityManager =
(AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
Resources r = context.getResources();
- mDefaultColor = mWhiteColor = r.getColor(R.color.clock_white);
+ mDefaultColor = mWhiteColor = Color.WHITE;
mPressedColor = mAccentColor = Utils.obtainStyledColor(
context, R.attr.colorAccent, Color.RED);
mBigFontSize = r.getDimension(R.dimen.big_font_size);
diff --git a/src/com/android/deskclock/timer/TimerCircleView.java b/src/com/android/deskclock/timer/TimerCircleView.java
index dd2c79f..6756631 100644
--- a/src/com/android/deskclock/timer/TimerCircleView.java
+++ b/src/com/android/deskclock/timer/TimerCircleView.java
@@ -70,7 +70,7 @@
mStrokeSize = resources.getDimension(R.dimen.circletimer_circle_size);
mRadiusOffset = Utils.calculateRadiusOffset(mStrokeSize, dotDiameter, 0);
- mRemainderColor = resources.getColor(R.color.clock_white);
+ mRemainderColor = Color.WHITE;
mCompletedColor = Utils.obtainStyledColor(context, R.attr.colorAccent, Color.RED);
mPaint.setAntiAlias(true);
diff --git a/src/com/android/deskclock/timer/TimerFragment.java b/src/com/android/deskclock/timer/TimerFragment.java
index 3577519..f861034 100644
--- a/src/com/android/deskclock/timer/TimerFragment.java
+++ b/src/com/android/deskclock/timer/TimerFragment.java
@@ -22,9 +22,9 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.os.Bundle;
import android.os.SystemClock;
+import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
@@ -43,6 +43,7 @@
import com.android.deskclock.data.Timer;
import com.android.deskclock.data.TimerListener;
import com.android.deskclock.events.Events;
+import com.android.deskclock.uidata.UiDataModel;
import java.io.Serializable;
import java.util.Arrays;
@@ -50,15 +51,17 @@
import static android.view.View.ALPHA;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
-import static android.view.View.OnClickListener;
import static android.view.View.SCALE_X;
import static android.view.View.VISIBLE;
-import static com.android.deskclock.AnimatorUtils.getScaleAnimator;
+import static com.android.deskclock.FabContainer.UpdateType.DISABLE_BUTTONS;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_AND_BUTTONS_ANIMATED;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_AND_BUTTONS_IMMEDIATE;
+import static com.android.deskclock.uidata.UiDataModel.Tab.TIMERS;
/**
* Displays a vertical list of timers in all states.
*/
-public class TimerFragment extends DeskClockFragment {
+public final class TimerFragment extends DeskClockFragment {
private static final String EXTRA_TIMER_SETUP = "com.android.deskclock.action.TIMER_SETUP";
@@ -76,27 +79,23 @@
private TimerSetupView mCreateTimerView;
private ViewPager mViewPager;
private TimerPagerAdapter mAdapter;
- private ImageButton mCancelCreateButton;
private View mTimersView;
private View mCurrentView;
private ImageView[] mPageIndicators;
- private int mShortAnimationDuration;
- private int mMediumAnimationDuration;
-
private Serializable mTimerSetupState;
/**
* @return an Intent that selects the timers tab with the setup screen for a new timer in place.
*/
public static Intent createTimerSetupIntent(Context context) {
- return new Intent(context, DeskClock.class)
- .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX)
- .putExtra(EXTRA_TIMER_SETUP, true);
+ return new Intent(context, DeskClock.class).putExtra(EXTRA_TIMER_SETUP, true);
}
/** The public no-arg constructor required by all fragments. */
- public TimerFragment() {}
+ public TimerFragment() {
+ super(TIMERS);
+ }
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -110,20 +109,13 @@
mTimersView = view.findViewById(R.id.timer_view);
mCreateTimerView = (TimerSetupView) view.findViewById(R.id.timer_setup);
+ mCreateTimerView.setFabContainer(this);
mPageIndicators = new ImageView[] {
(ImageView) view.findViewById(R.id.page_indicator0),
(ImageView) view.findViewById(R.id.page_indicator1),
(ImageView) view.findViewById(R.id.page_indicator2),
(ImageView) view.findViewById(R.id.page_indicator3)
};
- mCancelCreateButton = (ImageButton) view.findViewById(R.id.timer_cancel);
- mCancelCreateButton.setOnClickListener(new CancelCreateListener());
-
- view.findViewById(R.id.timer_create).setOnClickListener(new CreateListener());
-
- final Resources resources = getResources();
- mShortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime);
- mMediumAnimationDuration = resources.getInteger(android.R.integer.config_mediumAnimTime);
DataModel.getDataModel().addTimerListener(mAdapter);
DataModel.getDataModel().addTimerListener(mTimerWatcher);
@@ -140,9 +132,6 @@
public void onResume() {
super.onResume();
- // Start watching for page changes away from this fragment.
- getDeskClock().registerPageChangedListener(this);
-
// Initialize the page indicators.
updatePageIndicators();
@@ -163,11 +152,11 @@
// Choose the view to display in this fragment.
if (showTimerId != -1) {
// A specific timer must be shown; show the list of timers.
- showTimersView();
+ showTimersView(FAB_AND_BUTTONS_IMMEDIATE);
} else if (!hasTimers() || createTimer || mTimerSetupState != null) {
// No timers exist, a timer is being created, or the last view was timer setup;
// show the timer setup view.
- showCreateTimerView();
+ showCreateTimerView(FAB_AND_BUTTONS_IMMEDIATE);
if (mTimerSetupState != null) {
mCreateTimerView.setState(mTimerSetupState);
@@ -175,7 +164,7 @@
}
} else {
// Otherwise, default to showing the list of timers.
- showTimersView();
+ showTimersView(FAB_AND_BUTTONS_IMMEDIATE);
}
// If the intent did not specify a timer to show, show the last timer that expired.
@@ -195,14 +184,6 @@
}
@Override
- public void onPause() {
- super.onPause();
-
- // Stop watching for page changes away from this fragment.
- getDeskClock().unregisterPageChangedListener(this);
- }
-
- @Override
public void onStop() {
super.onStop();
@@ -230,101 +211,140 @@
}
@Override
- public void setFabAppearance() {
- if (mFab == null || getSelectedTab() != DeskClock.TIMER_TAB_INDEX) {
- return;
- }
-
+ public void onUpdateFab(@NonNull ImageView fab) {
if (mCurrentView == mTimersView) {
final Timer timer = getTimer();
if (timer == null) {
- mFab.setVisibility(INVISIBLE);
+ fab.setVisibility(INVISIBLE);
return;
}
- mFab.setVisibility(VISIBLE);
+ fab.setVisibility(VISIBLE);
switch (timer.getState()) {
case RUNNING:
- mFab.setImageResource(R.drawable.ic_pause_white_24dp);
- mFab.setContentDescription(getString(R.string.timer_stop));
+ fab.setImageResource(R.drawable.ic_pause_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.timer_stop));
break;
case RESET:
case PAUSED:
- mFab.setImageResource(R.drawable.ic_start_white_24dp);
- mFab.setContentDescription(getString(R.string.timer_start));
+ fab.setImageResource(R.drawable.ic_start_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.timer_start));
break;
case EXPIRED:
- mFab.setImageResource(R.drawable.ic_stop_white_24dp);
- mFab.setContentDescription(getString(R.string.timer_stop));
+ fab.setImageResource(R.drawable.ic_stop_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.timer_stop));
break;
}
} else if (mCurrentView == mCreateTimerView) {
- mFab.setVisibility(INVISIBLE);
+ if (mCreateTimerView.hasValidInput()) {
+ fab.setImageResource(R.drawable.ic_start_white_24dp);
+ fab.setContentDescription(fab.getResources().getString(R.string.timer_start));
+ fab.setVisibility(VISIBLE);
+ } else {
+ fab.setVisibility(INVISIBLE);
+ }
}
}
@Override
- public void onFabClick(View view) {
- final Timer timer = getTimer();
+ public void onUpdateFabButtons(@NonNull ImageButton left, @NonNull ImageButton right) {
+ if (mCurrentView == mTimersView) {
+ left.setEnabled(true);
+ left.setImageResource(R.drawable.ic_delete);
+ left.setContentDescription(left.getResources().getString(R.string.timer_delete));
+ left.setVisibility(mCurrentView != mTimersView ? GONE : VISIBLE);
- // If no timer is currently showing a fab action is meaningless.
- if (timer == null) {
- return;
- }
+ right.setEnabled(true);
+ right.setImageResource(R.drawable.ic_add_timer);
+ right.setContentDescription(right.getResources().getString(R.string.timer_add_timer));
+ right.setVisibility(mCurrentView != mTimersView ? GONE : VISIBLE);
- switch (timer.getState()) {
- case RUNNING:
- DataModel.getDataModel().pauseTimer(timer);
- Events.sendTimerEvent(R.string.action_stop, R.string.label_deskclock);
- break;
- case PAUSED:
- case RESET:
- DataModel.getDataModel().startTimer(timer);
- Events.sendTimerEvent(R.string.action_start, R.string.label_deskclock);
- break;
- case EXPIRED:
- DataModel.getDataModel().resetOrDeleteTimer(timer, R.string.label_deskclock);
- break;
+ } else if (mCurrentView == mCreateTimerView) {
+ left.setEnabled(true);
+ left.setImageResource(R.drawable.ic_cancel);
+ left.setContentDescription(left.getResources().getString(R.string.timer_cancel));
+ // If no timers yet exist, the user is forced to create the first one.
+ left.setVisibility(hasTimers() ? VISIBLE : INVISIBLE);
+
+ right.setVisibility(GONE);
}
}
@Override
- public void setLeftRightButtonAppearance() {
- if (mLeftButton == null || mRightButton == null ||
- getSelectedTab() != DeskClock.TIMER_TAB_INDEX) {
- return;
+ public void onFabClick(@NonNull ImageView fab) {
+ if (mCurrentView == mTimersView) {
+ final Timer timer = getTimer();
+
+ // If no timer is currently showing a fab action is meaningless.
+ if (timer == null) {
+ return;
+ }
+
+ switch (timer.getState()) {
+ case RUNNING:
+ DataModel.getDataModel().pauseTimer(timer);
+ Events.sendTimerEvent(R.string.action_stop, R.string.label_deskclock);
+ break;
+ case PAUSED:
+ case RESET:
+ DataModel.getDataModel().startTimer(timer);
+ Events.sendTimerEvent(R.string.action_start, R.string.label_deskclock);
+ break;
+ case EXPIRED:
+ DataModel.getDataModel().resetOrDeleteTimer(timer, R.string.label_deskclock);
+ break;
+ }
+
+ } else if (mCurrentView == mCreateTimerView) {
+ // Create the new timer.
+ final long length = mCreateTimerView.getTimeInMillis();
+ final Timer timer = DataModel.getDataModel().addTimer(length, "", false);
+ Events.sendTimerEvent(R.string.action_create, R.string.label_deskclock);
+
+ // Start the new timer.
+ DataModel.getDataModel().startTimer(timer);
+ Events.sendTimerEvent(R.string.action_start, R.string.label_deskclock);
+
+ // Reset the state of the create view.
+ mCreateTimerView.reset();
+
+ // Display the freshly created timer view.
+ mViewPager.setCurrentItem(0);
+
+ // Return to the list of timers.
+ animateToView(mTimersView, null);
}
-
- mLeftButton.setEnabled(true);
- mLeftButton.setImageResource(R.drawable.ic_delete);
- mLeftButton.setContentDescription(getString(R.string.timer_delete));
- mLeftButton.setVisibility(mCurrentView != mTimersView ? GONE : VISIBLE);
-
- mRightButton.setEnabled(true);
- mRightButton.setImageResource(R.drawable.ic_add_timer);
- mRightButton.setContentDescription(getString(R.string.timer_add_timer));
- mRightButton.setVisibility(mCurrentView != mTimersView ? GONE : VISIBLE);
}
@Override
- public void onLeftButtonClick(View view) {
- final Timer timer = getTimer();
- if (timer == null) {
- return;
- }
+ public void onLeftButtonClick(@NonNull ImageButton left) {
+ if (mCurrentView == mTimersView) {
+ final Timer timer = getTimer();
+ if (timer == null) {
+ return;
+ }
- if (mAdapter.getCount() > 1) {
- animateTimerRemove(timer);
- } else {
- animateToView(mCreateTimerView, timer);
- }
+ if (mAdapter.getCount() > 1) {
+ animateTimerRemove(timer);
+ } else {
+ animateToView(mCreateTimerView, timer);
+ }
- view.announceForAccessibility(getActivity().getString(R.string.timer_deleted));
+ left.announceForAccessibility(getActivity().getString(R.string.timer_deleted));
+
+ } else if (mCurrentView == mCreateTimerView) {
+ // Clicking the X icon on the timer creation page returns to the timers list.
+ mCreateTimerView.reset();
+
+ animateToView(mTimersView, null);
+
+ left.announceForAccessibility(getActivity().getString(R.string.timer_canceled));
+ }
}
@Override
- public void onRightButtonClick(View view) {
+ public void onRightButtonClick(@NonNull ImageButton right) {
animateToView(mCreateTimerView, null);
}
@@ -409,14 +429,10 @@
/**
* Display the view that creates a new timer.
*/
- private void showCreateTimerView() {
+ private void showCreateTimerView(UpdateType updateType) {
// Stop animating the timers.
stopUpdatingTime();
- // If no timers yet exist, the user is forced to create the first one.
- mCancelCreateButton.setVisibility(hasTimers() ? VISIBLE : INVISIBLE);
- mCancelCreateButton.setEnabled(true);
-
// Show the creation view; hide the timer view.
mTimersView.setVisibility(GONE);
mCreateTimerView.setVisibility(VISIBLE);
@@ -425,14 +441,13 @@
mCurrentView = mCreateTimerView;
// Update the fab and buttons.
- setLeftRightButtonAppearance();
- setFabAppearance();
+ updateFab(updateType);
}
/**
* Display the view that lists all existing timers.
*/
- private void showTimersView() {
+ private void showTimersView(UpdateType updateType) {
// Show the timer view; hide the creation view.
mTimersView.setVisibility(VISIBLE);
mCreateTimerView.setVisibility(GONE);
@@ -441,8 +456,7 @@
mCurrentView = mTimersView;
// Update the fab and buttons.
- setLeftRightButtonAppearance();
- setFabAppearance();
+ updateFab(updateType);
// Start animating the timers.
startUpdatingTime();
@@ -452,8 +466,10 @@
* @param timerToRemove the timer to be removed during the animation
*/
private void animateTimerRemove(final Timer timerToRemove) {
+ final long duration = UiDataModel.getUiDataModel().getShortAnimationDuration();
+
final Animator fadeOut = ObjectAnimator.ofFloat(mViewPager, ALPHA, 1, 0);
- fadeOut.setDuration(mShortAnimationDuration);
+ fadeOut.setDuration(duration);
fadeOut.setInterpolator(new DecelerateInterpolator());
fadeOut.addListener(new AnimatorListenerAdapter() {
@Override
@@ -464,7 +480,7 @@
});
final Animator fadeIn = ObjectAnimator.ofFloat(mViewPager, ALPHA, 0, 1);
- fadeIn.setDuration(mShortAnimationDuration);
+ fadeIn.setDuration(duration);
fadeIn.setInterpolator(new AccelerateInterpolator());
final AnimatorSet animatorSet = new AnimatorSet();
@@ -485,12 +501,11 @@
final boolean toTimers = toView == mTimersView;
// Avoid double-taps by enabling/disabling the set of buttons active on the new view.
- mLeftButton.setEnabled(toTimers);
- mRightButton.setEnabled(toTimers);
- mCancelCreateButton.setEnabled(!toTimers);
+ updateFab(DISABLE_BUTTONS);
+ final long duration = UiDataModel.getUiDataModel().getShortAnimationDuration();
final Animator rotateFrom = ObjectAnimator.ofFloat(mCurrentView, SCALE_X, 1, 0);
- rotateFrom.setDuration(mShortAnimationDuration);
+ rotateFrom.setDuration(duration);
rotateFrom.setInterpolator(new DecelerateInterpolator());
rotateFrom.addListener(new AnimatorListenerAdapter() {
@Override
@@ -502,43 +517,19 @@
mCurrentView.setScaleX(1);
if (toTimers) {
- showTimersView();
+ showTimersView(FAB_AND_BUTTONS_ANIMATED);
} else {
- showCreateTimerView();
+ showCreateTimerView(FAB_AND_BUTTONS_ANIMATED);
}
}
});
final Animator rotateTo = ObjectAnimator.ofFloat(toView, SCALE_X, 0, 1);
- rotateTo.setDuration(mShortAnimationDuration);
+ rotateTo.setDuration(duration);
rotateTo.setInterpolator(new AccelerateInterpolator());
- final float preScale = toTimers ? 0 : 1;
- final float postScale = toTimers ? 1 : 0;
- final Animator fabAnimator = getScaleAnimator(mFab, preScale, postScale);
- final Animator leftButtonAnimator = getScaleAnimator(mLeftButton, preScale, postScale);
- final Animator rightButtonAnimator = getScaleAnimator(mRightButton, preScale, postScale);
-
- final AnimatorSet buttons = new AnimatorSet();
- buttons.setDuration(toTimers ? mMediumAnimationDuration : mShortAnimationDuration);
- buttons.play(leftButtonAnimator).with(rightButtonAnimator).with(fabAnimator);
- buttons.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLeftButton.setVisibility(toTimers ? VISIBLE : INVISIBLE);
- mRightButton.setVisibility(toTimers ? VISIBLE : INVISIBLE);
-
- mFab.setScaleX(1);
- mFab.setScaleY(1);
- mLeftButton.setScaleX(1);
- mLeftButton.setScaleY(1);
- mRightButton.setScaleX(1);
- mRightButton.setScaleY(1);
- }
- });
-
final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.play(rotateFrom).before(rotateTo).with(buttons);
+ animatorSet.play(rotateFrom).before(rotateTo);
animatorSet.start();
}
@@ -551,7 +542,7 @@
return null;
}
- return mAdapter.getTimer(mViewPager.getCurrentItem());
+ return mAdapter.getCount() == 0 ? null : mAdapter.getTimer(mViewPager.getCurrentItem());
}
private void startUpdatingTime() {
@@ -590,7 +581,7 @@
@Override
public void onPageSelected(int position) {
updatePageIndicators();
- setFabAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
// Showing a new timer page may introduce a timer requiring continuous updates.
startUpdatingTime();
@@ -641,9 +632,9 @@
if (!before.isExpired() && after.isExpired() && index != mViewPager.getCurrentItem()) {
mViewPager.setCurrentItem(index, true);
- } else if (index == mViewPager.getCurrentItem()) {
+ } else if (mCurrentView == mTimersView && index == mViewPager.getCurrentItem()) {
// If the visible timer changed, update the fab to match its new state.
- setFabAppearance();
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
}
}
@@ -656,50 +647,7 @@
}
updatePageIndicators();
- }
- }
-
- /**
- * Clicking the play icon on the timer creation page creates a new timer and returns to the
- * timers list.
- */
- private class CreateListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- // Create the new timer.
- final long length = mCreateTimerView.getTimeInMillis();
- final Timer timer = DataModel.getDataModel().addTimer(length, "", false);
- Events.sendTimerEvent(R.string.action_create, R.string.label_deskclock);
-
- // Start the new timer.
- DataModel.getDataModel().startTimer(timer);
- Events.sendTimerEvent(R.string.action_start, R.string.label_deskclock);
-
- // Reset the state of the create view.
- mCreateTimerView.reset();
-
- // Display the freshly created timer view.
- mViewPager.setCurrentItem(0);
-
- // Return to the list of timers.
- animateToView(mTimersView, null);
- }
- }
-
- /**
- * Clicking the X icon on the timer creation page returns to the timers list.
- */
- private class CancelCreateListener implements OnClickListener {
- @Override
- public void onClick(View view) {
- // Reset the state of the create view.
- mCreateTimerView.reset();
-
- if (hasTimers()) {
- animateToView(mTimersView, null);
- }
-
- view.announceForAccessibility(getActivity().getString(R.string.timer_canceled));
+ updateFab(FAB_AND_BUTTONS_IMMEDIATE);
}
}
}
\ No newline at end of file
diff --git a/src/com/android/deskclock/timer/TimerItem.java b/src/com/android/deskclock/timer/TimerItem.java
index e5a7be1..9c9b12e 100644
--- a/src/com/android/deskclock/timer/TimerItem.java
+++ b/src/com/android/deskclock/timer/TimerItem.java
@@ -31,7 +31,7 @@
/**
* This view is a visual representation of a {@link Timer}.
*/
-class TimerItem extends LinearLayout {
+public class TimerItem extends LinearLayout {
/** Displays the remaining time or time since expiration. */
private CountingTimerView mTimerText;
@@ -125,4 +125,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/timer/TimerKlaxon.java b/src/com/android/deskclock/timer/TimerKlaxon.java
index 979d937..c2f6dc1 100644
--- a/src/com/android/deskclock/timer/TimerKlaxon.java
+++ b/src/com/android/deskclock/timer/TimerKlaxon.java
@@ -16,15 +16,21 @@
package com.android.deskclock.timer;
+import android.annotation.TargetApi;
import android.content.Context;
+import android.media.AudioAttributes;
import android.net.Uri;
+import android.os.Build;
+import android.os.Vibrator;
import com.android.deskclock.AsyncRingtonePlayer;
import com.android.deskclock.LogUtils;
+import com.android.deskclock.Utils;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.settings.SettingsActivity;
public abstract class TimerKlaxon {
+ private static final long[] VIBRATE_PATTERN = {500, 500};
private static boolean sStarted = false;
private static AsyncRingtonePlayer sAsyncRingtonePlayer;
@@ -37,6 +43,7 @@
LogUtils.i("TimerKlaxon.stop()");
sStarted = false;
getAsyncRingtonePlayer(context).stop();
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).cancel();
}
}
@@ -53,9 +60,30 @@
final Uri uri = DataModel.getDataModel().getTimerRingtoneUri();
getAsyncRingtonePlayer(context).play(uri);
}
+
+ if (DataModel.getDataModel().getTimerVibrate()) {
+ final Vibrator vibrator = getVibrator(context);
+ if (Utils.isLOrLater()) {
+ vibrateLOrLater(vibrator);
+ } else {
+ vibrator.vibrate(VIBRATE_PATTERN, 0);
+ }
+ }
sStarted = true;
}
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private static void vibrateLOrLater(Vibrator vibrator) {
+ vibrator.vibrate(VIBRATE_PATTERN, 0, new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ALARM)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build());
+ }
+
+ private static Vibrator getVibrator(Context context) {
+ return ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE));
+ }
+
private static synchronized AsyncRingtonePlayer getAsyncRingtonePlayer(Context context) {
if (sAsyncRingtonePlayer == null) {
sAsyncRingtonePlayer = new AsyncRingtonePlayer(context.getApplicationContext(),
diff --git a/src/com/android/deskclock/timer/TimerSetupView.java b/src/com/android/deskclock/timer/TimerSetupView.java
index d854379..58f9815 100644
--- a/src/com/android/deskclock/timer/TimerSetupView.java
+++ b/src/com/android/deskclock/timer/TimerSetupView.java
@@ -16,57 +16,43 @@
package com.android.deskclock.timer;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
+import android.support.v4.content.ContextCompat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import com.android.deskclock.AnimatorUtils;
+import com.android.deskclock.FabContainer;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import java.io.Serializable;
import java.util.Arrays;
+import static com.android.deskclock.FabContainer.UpdateType.FAB_ONLY_ANIMATED;
+
public class TimerSetupView extends LinearLayout implements Button.OnClickListener,
Button.OnLongClickListener {
private final Button[] mNumbers = new Button[10];
- private final int[] mInput = new int[6];
+ private final int[] mInput = {0, 0, 0, 0, 0, 0};
private int mInputPointer = -1;
- private ImageView mCreate;
private ImageButton mDelete;
private TimerView mEnteredTime;
private View mDivider;
+ /** Updates to the fab are requested via this container. */
+ private FabContainer mFabContainer;
+
private final int mColorAccent;
private final int mColorHairline;
- private final AnimatorListenerAdapter mHideCreateListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCreate.setScaleX(1);
- mCreate.setScaleY(1);
- mCreate.setVisibility(INVISIBLE);
- }
- };
-
- private final AnimatorListenerAdapter mShowCreateListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mCreate.setVisibility(VISIBLE);
- }
- };
-
public TimerSetupView(Context context) {
this(context, null /* attrs */);
}
@@ -75,11 +61,15 @@
super(context, attrs);
mColorAccent = Utils.obtainStyledColor(context, R.attr.colorAccent, Color.RED);
- mColorHairline = context.getResources().getColor(R.color.hairline);
+ mColorHairline = ContextCompat.getColor(context, R.color.hairline);
LayoutInflater.from(context).inflate(R.layout.time_setup_view, this);
}
+ void setFabContainer(FabContainer fabContainer) {
+ mFabContainer = fabContainer;
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -90,7 +80,6 @@
final View v4 = findViewById(R.id.fourth);
mDivider = findViewById(R.id.divider);
- mCreate = (ImageView) findViewById(R.id.timer_create);
mDelete = (ImageButton) findViewById(R.id.delete);
mDelete.setOnClickListener(this);
mDelete.setOnLongClickListener(this);
@@ -119,11 +108,12 @@
mNumbers[i].setTag(R.id.numbers_key, i);
}
- reset();
+ updateTime();
}
@Override
public void onClick(View v) {
+ final boolean validInputBeforeClick = hasValidInput();
final Integer n = (Integer) v.getTag(R.id.numbers_key);
// A number was pressed
if (n != null) {
@@ -167,28 +157,29 @@
mDelete.setContentDescription(cd);
}
- updateStartButton();
- updateDeleteButtonAndDivider();
+ if (validInputBeforeClick != hasValidInput()) {
+ updateFab();
+ updateDeleteButtonAndDivider();
+ }
}
@Override
public boolean onLongClick(View v) {
if (v == mDelete) {
reset();
- updateStartButton();
return true;
}
return false;
}
public void reset() {
- for (int i = 0; i < mInput.length; i ++) {
- mInput[i] = 0;
+ if (mInputPointer != -1) {
+ Arrays.fill(mInput, 0);
+ mInputPointer = -1;
+ updateFab();
+ updateTime();
+ updateDeleteButtonAndDivider();
}
- mInputPointer = -1;
- updateTime();
- updateDeleteButtonAndDivider();
- mCreate.setVisibility(INVISIBLE);
}
public long getTimeInMillis() {
@@ -221,38 +212,25 @@
}
updateTime();
updateDeleteButtonAndDivider();
- mCreate.setVisibility(getInputExists() ? VISIBLE : INVISIBLE);
}
}
+ protected boolean hasValidInput() {
+ return mInputPointer != -1;
+ }
+
private void updateTime() {
final int seconds = mInput[1] * 10 + mInput[0];
mEnteredTime.setTime(mInput[5], mInput[4], mInput[3], mInput[2], seconds);
}
- private void updateStartButton() {
- final boolean show = getInputExists();
- final int finalVisibility = show ? VISIBLE : INVISIBLE;
- if (mCreate.getVisibility() == finalVisibility) {
- // Fab is not initialized yet or already shown/hidden
- return;
- }
-
- final int from = show ? 0 : 1;
- final int to = show ? 1 : 0;
- final Animator scaleAnimator = AnimatorUtils.getScaleAnimator(mCreate, from, to);
- scaleAnimator.setDuration(AnimatorUtils.ANIM_DURATION_SHORT);
- scaleAnimator.addListener(show ? mShowCreateListener : mHideCreateListener);
- scaleAnimator.start();
- }
-
private void updateDeleteButtonAndDivider() {
- final boolean enabled = getInputExists();
+ final boolean enabled = hasValidInput();
mDelete.setEnabled(enabled);
mDivider.setBackgroundColor(enabled ? mColorAccent : mColorHairline);
}
- private boolean getInputExists() {
- return mInputPointer != -1;
+ private void updateFab() {
+ mFabContainer.updateFab(FAB_ONLY_ANIMATED);
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/deskclock/timer/TimerView.java b/src/com/android/deskclock/timer/TimerView.java
index 3fde57b..eddd1ae 100644
--- a/src/com/android/deskclock/timer/TimerView.java
+++ b/src/com/android/deskclock/timer/TimerView.java
@@ -17,9 +17,9 @@
package com.android.deskclock.timer;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Typeface;
+import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -48,9 +48,8 @@
mAndroidClockMonoThin =
Typeface.createFromAsset(context.getAssets(), "fonts/AndroidClockMono-Thin.ttf");
- final Resources resources = context.getResources();
- mWhiteColor = resources.getColor(R.color.clock_white);
- mGrayColor = resources.getColor(R.color.clock_gray);
+ mWhiteColor = ContextCompat.getColor(context, R.color.clock_white);
+ mGrayColor = ContextCompat.getColor(context, R.color.clock_gray);
}
@Override
diff --git a/src/com/android/deskclock/uidata/TabDAO.java b/src/com/android/deskclock/uidata/TabDAO.java
new file mode 100644
index 0000000..2b8aba8
--- /dev/null
+++ b/src/com/android/deskclock/uidata/TabDAO.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.uidata;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import static com.android.deskclock.uidata.UiDataModel.Tab;
+
+/**
+ * This class encapsulates the storage of tab data in {@link SharedPreferences}.
+ */
+final class TabDAO {
+
+ private static final String KEY_SELECTED_TAB = "selected_tab";
+
+ // Lazily instantiated and cached for the life of the application.
+ private static SharedPreferences sPrefs;
+
+ private TabDAO() {}
+
+ /**
+ * @return an enumerated value indicating the currently selected primary tab
+ */
+ static Tab getSelectedTab(Context context) {
+ final SharedPreferences prefs = getSharedPreferences(context);
+ final int selectedTabOrdinal = prefs.getInt(KEY_SELECTED_TAB, Tab.CLOCKS.ordinal());
+ return Tab.values()[selectedTabOrdinal];
+ }
+
+ /**
+ * @param tab an enumerated value indicating the newly selected primary tab
+ */
+ static void setSelectedTab(Context context, Tab tab) {
+ getSharedPreferences(context).edit().putInt(KEY_SELECTED_TAB, tab.ordinal()).apply();
+ }
+
+ private static SharedPreferences getSharedPreferences(Context context) {
+ if (sPrefs == null) {
+ sPrefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ }
+
+ return sPrefs;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/uidata/TabListener.java b/src/com/android/deskclock/uidata/TabListener.java
new file mode 100644
index 0000000..918b893
--- /dev/null
+++ b/src/com/android/deskclock/uidata/TabListener.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.uidata;
+
+import com.android.deskclock.uidata.UiDataModel.Tab;
+
+/**
+ * The interface through which interested parties are notified of changes to the selected tab.
+ */
+public interface TabListener {
+
+ /**
+ * @param oldSelectedTab an enumerated value indicating the prior selected tab
+ * @param newSelectedTab an enumerated value indicating the newly selected tab
+ */
+ void selectedTabChanged(Tab oldSelectedTab, Tab newSelectedTab);
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/uidata/TabModel.java b/src/com/android/deskclock/uidata/TabModel.java
new file mode 100644
index 0000000..cbceda6
--- /dev/null
+++ b/src/com/android/deskclock/uidata/TabModel.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.uidata;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+import static com.android.deskclock.uidata.UiDataModel.Tab;
+
+/**
+ * All tab data is accessed via this model.
+ */
+final class TabModel {
+
+ private final Context mContext;
+
+ /** The listeners to notify when the selected tab is changed. */
+ private final List<TabListener> mTabListeners = new ArrayList<>();
+
+ /** An enumerated value indicating the currently selected tab. */
+ private Tab mSelectedTab;
+
+ TabModel(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * @param tabListener to be notified when the selected tab changes
+ */
+ void addTabListener(TabListener tabListener) {
+ mTabListeners.add(tabListener);
+ }
+
+ /**
+ * @param tabListener to no longer be notified when the selected tab changes
+ */
+ void removeTabListener(TabListener tabListener) {
+ mTabListeners.remove(tabListener);
+ }
+
+ /**
+ * @return the number of tabs
+ */
+ int getTabCount() {
+ return Tab.values().length;
+ }
+
+ /**
+ * @param index the index of the tab
+ * @return the tab at the given {@code index}
+ */
+ Tab getTab(int index) {
+ return Tab.values()[index];
+ }
+
+ /**
+ * @return the index of the currently selected primary tab
+ */
+ int getSelectedTabIndex() {
+ return getSelectedTab().ordinal();
+ }
+
+ /**
+ * @param index the index of the tab to select
+ */
+ void setSelectedTabIndex(int index) {
+ setSelectedTab(Tab.values()[index]);
+ }
+
+ /**
+ * @return an enumerated value indicating the currently selected primary tab
+ */
+ Tab getSelectedTab() {
+ if (mSelectedTab == null) {
+ mSelectedTab = TabDAO.getSelectedTab(mContext);
+ }
+ return mSelectedTab;
+ }
+
+ /**
+ * @param tab an enumerated value indicating the newly selected primary tab
+ */
+ void setSelectedTab(Tab tab) {
+ final Tab oldSelectedTab = getSelectedTab();
+ if (oldSelectedTab != tab) {
+ mSelectedTab = tab;
+ TabDAO.setSelectedTab(mContext, tab);
+
+ for (TabListener tl : mTabListeners) {
+ tl.selectedTabChanged(oldSelectedTab, tab);
+ }
+ }
+ }
+
+ /**
+ * @param ltrTabIndex the tab index assuming left-to-right layout direction
+ * @return the tab index in the current layout direction
+ */
+ int getTabLayoutIndex(int ltrTabIndex) {
+ if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == LAYOUT_DIRECTION_RTL) {
+ return getTabCount() - ltrTabIndex - 1;
+ }
+ return ltrTabIndex;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/uidata/UiDataModel.java b/src/com/android/deskclock/uidata/UiDataModel.java
new file mode 100644
index 0000000..8f5326d
--- /dev/null
+++ b/src/com/android/deskclock/uidata/UiDataModel.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.deskclock.uidata;
+
+import android.content.Context;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.StringRes;
+
+import com.android.deskclock.AlarmClockFragment;
+import com.android.deskclock.ClockFragment;
+import com.android.deskclock.R;
+import com.android.deskclock.stopwatch.StopwatchFragment;
+import com.android.deskclock.timer.TimerFragment;
+
+import static com.android.deskclock.Utils.enforceMainLooper;
+
+/**
+ * All application-wide user interface data is accessible through this singleton.
+ */
+public final class UiDataModel {
+
+ /** Identifies each of the primary tabs within the application. */
+ public enum Tab {
+ ALARMS(AlarmClockFragment.class, R.drawable.ic_tab_alarm, R.string.menu_alarm),
+ CLOCKS(ClockFragment.class, R.drawable.ic_tab_clock, R.string.menu_clock),
+ TIMERS(TimerFragment.class, R.drawable.ic_tab_timer, R.string.menu_timer),
+ STOPWATCH(StopwatchFragment.class, R.drawable.ic_tab_stopwatch, R.string.menu_stopwatch);
+
+ private final String mFragmentClassName;
+ private final @DrawableRes int mIconId;
+ private final @StringRes int mContentDescriptionId;
+
+ Tab(Class fragmentClass, @DrawableRes int iconId, @StringRes int contentDescriptionId) {
+ mFragmentClassName = fragmentClass.getName();
+ mIconId = iconId;
+ mContentDescriptionId = contentDescriptionId;
+ }
+
+ public String getFragmentClassName() { return mFragmentClassName; }
+ public int getIconId() { return mIconId; }
+ public int getContentDescriptionId() { return mContentDescriptionId; }
+ }
+
+ /** The single instance of this data model that exists for the life of the application. */
+ private static final UiDataModel sUiDataModel = new UiDataModel();
+
+ public static UiDataModel getUiDataModel() {
+ return sUiDataModel;
+ }
+
+ private Context mContext;
+
+ /** The model from which tab data are fetched. */
+ private TabModel mTabModel;
+
+ private UiDataModel() {}
+
+ /**
+ * The context may be set precisely once during the application life.
+ */
+ public void setContext(Context context) {
+ if (mContext != null) {
+ throw new IllegalStateException("context has already been set");
+ }
+ mContext = context.getApplicationContext();
+
+ mTabModel = new TabModel(mContext);
+ }
+
+ //
+ // Animations
+ //
+
+ /**
+ * @return the duration in milliseconds of short animations
+ */
+ public long getShortAnimationDuration() {
+ enforceMainLooper();
+ return mContext.getResources().getInteger(android.R.integer.config_shortAnimTime);
+ }
+
+ //
+ // Tabs
+ //
+
+ /**
+ * @param tabListener to be notified when the selected tab changes
+ */
+ public void addTabListener(TabListener tabListener) {
+ enforceMainLooper();
+ mTabModel.addTabListener(tabListener);
+ }
+
+ /**
+ * @param tabListener to no longer be notified when the selected tab changes
+ */
+ public void removeTabListener(TabListener tabListener) {
+ enforceMainLooper();
+ mTabModel.removeTabListener(tabListener);
+ }
+
+ /**
+ * @return the number of tabs
+ */
+ public int getTabCount() {
+ enforceMainLooper();
+ return mTabModel.getTabCount();
+ }
+
+ /**
+ * @param index the index of the tab
+ * @return the tab at the given {@code index}
+ */
+ public Tab getTab(int index) {
+ enforceMainLooper();
+ return mTabModel.getTab(index);
+ }
+
+ /**
+ * @return the index of the currently selected primary tab
+ */
+ public int getSelectedTabIndex() {
+ enforceMainLooper();
+ return mTabModel.getSelectedTabIndex();
+ }
+
+ /**
+ * @param index the index of the tab to select
+ */
+ public void setSelectedTabIndex(int index) {
+ enforceMainLooper();
+ mTabModel.setSelectedTabIndex(index);
+ }
+
+ /**
+ * @return an enumerated value indicating the currently selected primary tab
+ */
+ public Tab getSelectedTab() {
+ enforceMainLooper();
+ return mTabModel.getSelectedTab();
+ }
+
+ /**
+ * @param tab an enumerated value indicating the newly selected primary tab
+ */
+ public void setSelectedTab(Tab tab) {
+ enforceMainLooper();
+ mTabModel.setSelectedTab(tab);
+ }
+
+ /**
+ * This method converts the given {@code ltrTabIndex} which assumes Left-To-Right layout of the
+ * tabs into an index that respects the system layout, which may be Left-To-Right or
+ * Right-To-Left.
+ *
+ * @param ltrTabIndex the tab index assuming left-to-right layout direction
+ * @return the tab index in the current layout direction
+ */
+ public int getTabLayoutIndex(int ltrTabIndex) {
+ enforceMainLooper();
+ return mTabModel.getTabLayoutIndex(ltrTabIndex);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/deskclock/widget/RtlViewPager.java b/src/com/android/deskclock/widget/RtlViewPager.java
index fc2f43e..4af461a 100644
--- a/src/com/android/deskclock/widget/RtlViewPager.java
+++ b/src/com/android/deskclock/widget/RtlViewPager.java
@@ -18,11 +18,9 @@
import android.content.Context;
import android.support.v4.view.ViewPager;
-import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.View;
-import java.util.Locale;
+import com.android.deskclock.uidata.UiDataModel;
/**
* A {@link ViewPager} that's aware of RTL changes when used with FragmentPagerAdapter.
@@ -46,54 +44,46 @@
addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float offset, int offsetPixels) {
- // Do nothing
+ if (mListener != null) {
+ position = UiDataModel.getUiDataModel().getTabLayoutIndex(position);
+ mListener.onPageScrolled(position, offset, offsetPixels);
+ }
}
@Override
public void onPageSelected(int position) {
if (mListener != null) {
- mListener.onPageSelected(getRtlAwareIndex(position));
+ position = UiDataModel.getUiDataModel().getTabLayoutIndex(position);
+ mListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
- // Do nothing
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
}
});
}
@Override
public int getCurrentItem() {
- return getRtlAwareIndex(super.getCurrentItem());
+ return UiDataModel.getUiDataModel().getTabLayoutIndex(super.getCurrentItem());
}
@Override
public void setCurrentItem(int item) {
- super.setCurrentItem(getRtlAwareIndex(item));
+ super.setCurrentItem(UiDataModel.getUiDataModel().getTabLayoutIndex(item));
}
@Override
+ @SuppressWarnings("deprecation")
public void setOnPageChangeListener(OnPageChangeListener unused) {
throw new UnsupportedOperationException("Use setOnRTLPageChangeListener instead");
}
/**
- * Get a "RTL friendly" index. If the locale is LTR, the index is returned as is.
- * Otherwise it's transformed so view pager can render views using the new index for RTL. For
- * example, the second view will be rendered to the left of first view.
- *
- * @param index The logical index.
- */
- public int getRtlAwareIndex(int index) {
- if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) ==
- View.LAYOUT_DIRECTION_RTL) {
- return getAdapter().getCount() - index - 1;
- }
- return index;
- }
-
- /**
* Sets a {@link OnPageChangeListener}. The listener will be called when a page is selected.
*/
public void setOnRTLPageChangeListener(OnPageChangeListener listener) {
diff --git a/src/com/android/deskclock/widget/TextTime.java b/src/com/android/deskclock/widget/TextTime.java
index ff90a55..b1e23b5 100644
--- a/src/com/android/deskclock/widget/TextTime.java
+++ b/src/com/android/deskclock/widget/TextTime.java
@@ -141,7 +141,7 @@
}
public void setFormat(Context context) {
- setFormat12Hour(Utils.get12ModeFormat(context, true /* showAmPm */));
+ setFormat12Hour(Utils.get12ModeFormat(context, 0.22f /* amPmRatio */));
setFormat24Hour(Utils.get24ModeFormat());
}
diff --git a/src/com/android/deskclock/worldclock/CitySelectionActivity.java b/src/com/android/deskclock/worldclock/CitySelectionActivity.java
index d38ac71..580eaed 100644
--- a/src/com/android/deskclock/worldclock/CitySelectionActivity.java
+++ b/src/com/android/deskclock/worldclock/CitySelectionActivity.java
@@ -17,7 +17,6 @@
package com.android.deskclock.worldclock;
import android.content.Context;
-import android.media.AudioManager;
import android.os.Bundle;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
@@ -80,7 +79,7 @@
private CityAdapter mCitiesAdapter;
/** Manages all action bar menu display and click handling. */
- private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager(this);
+ private final ActionBarMenuManager mActionBarMenuManager = new ActionBarMenuManager();
/** Menu item controller for search view. */
private SearchMenuItemController mSearchMenuItemController;
@@ -88,7 +87,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setVolumeControlStream(AudioManager.STREAM_ALARM);
setContentView(R.layout.cities_activity);
mSearchMenuItemController =
@@ -467,7 +465,7 @@
*/
private void filter(String queryText) {
mSearchMenuItemController.setQueryText(queryText);
- final String query = queryText.trim().toUpperCase();
+ final String query = City.removeSpecialCharacters(queryText.toUpperCase());
// Compute the filtered list of cities.
final List<City> filteredCities;
@@ -477,7 +475,7 @@
final List<City> unselected = DataModel.getDataModel().getUnselectedCities();
filteredCities = new ArrayList<>(unselected.size());
for (City city : unselected) {
- if (city.getNameUpperCase().startsWith(query)) {
+ if (city.matches(query)) {
filteredCities.add(city);
}
}