summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhoffc <hoffc@codeaurora.org>2016-05-10 17:06:13 +0800
committerLinux Build Service Account <lnxbuild@localhost>2016-08-24 08:06:58 -0600
commit3f6f404180ea40416cf517838eec2744b6ec5a68 (patch)
treea07d3d2ff1d34bbb4568005bf327a68f70219bad
parenta9879bf10566963bbdc6cb42a79356ad39b9fbd5 (diff)
downloadandroid_packages_apps_DeskClock-3f6f404180ea40416cf517838eec2744b6ec5a68.tar.gz
android_packages_apps_DeskClock-3f6f404180ea40416cf517838eec2744b6ec5a68.tar.bz2
android_packages_apps_DeskClock-3f6f404180ea40416cf517838eec2744b6ec5a68.zip
DeskClock: Implement QTI Enchanced features for Android N
(1) support delay alarm feature when phone_hook state (2) support force alarm alert when device volume is zero (3) support missed the alarm feature when phone_hook state (4) Ux enhance feature: support audio media in SDCard as the alarm alert feature (5) Ux enhance feature: add default alarm alert setting item to Setting Actitiy (6) Ux enhance feature: support manual add city&timezone pair to City DB (7) Ux enhance feature: shake do specified action when alarm alerting (8) Ux enhance feature: flip do specified action when alarm alerting CRs-Fixed: 1014635 Change-Id: I8b027479025e535248dd3e575bc062cedb7c33ae
-rwxr-xr-xres/drawable-hdpi/ic_actionbar_add.pngbin0 -> 1058 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-hdpi/ic_gps_disabled.pngbin1564 -> 1376 bytes
-rw-r--r--res/drawable-hdpi/ic_gps_off.pngbin1567 -> 0 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-hdpi/ic_gps_on.pngbin1974 -> 1409 bytes
-rwxr-xr-xres/drawable-mdpi/ic_actionbar_add.pngbin0 -> 992 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-mdpi/ic_gps_disabled.pngbin985 -> 1205 bytes
-rw-r--r--res/drawable-mdpi/ic_gps_off.pngbin926 -> 0 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-mdpi/ic_gps_on.pngbin1268 -> 1217 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_actionbar_add.pngbin0 -> 1052 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-xhdpi/ic_gps_disabled.pngbin2253 -> 1487 bytes
-rw-r--r--res/drawable-xhdpi/ic_gps_off.pngbin2324 -> 0 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-xhdpi/ic_gps_on.pngbin2878 -> 1587 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_actionbar_add.pngbin0 -> 1108 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_gps_disabled.pngbin0 -> 1791 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_gps_on.pngbin0 -> 1966 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable/holo_selector_nonfocusable.xml12
-rwxr-xr-x[-rw-r--r--]res/drawable/ic_gps.xml5
-rwxr-xr-x[-rw-r--r--]res/drawable/ic_gps_anim.xml2
-rwxr-xr-x[-rw-r--r--]res/layout/city_add.xml95
-rwxr-xr-xres/layout/time_zone_list.xml44
-rwxr-xr-xres/layout/time_zone_list_item.xml52
-rw-r--r--res/menu/desk_clock_menu.xml5
-rw-r--r--res/values-zh-rCN/strings.xml17
-rw-r--r--res/values/array.xml5
-rw-r--r--res/values/colors.xml1
-rw-r--r--res/values/config.xml1
-rwxr-xr-x[-rw-r--r--]res/values/strings.xml54
-rw-r--r--res/xml/backup_scheme.xml4
-rwxr-xr-x[-rw-r--r--]res/xml/settings.xml29
-rw-r--r--src/com/android/deskclock/AlarmClockFragment.java108
-rw-r--r--src/com/android/deskclock/AlarmUtils.java36
-rw-r--r--src/com/android/deskclock/AsyncRingtonePlayer.java5
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/Utils.java76
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/alarms/AlarmService.java63
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/alarms/AlarmStateManager.java156
-rw-r--r--src/com/android/deskclock/alarms/AlarmTimeClickHandler.java69
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/alarms/PhoneStateReceiver.java3
-rw-r--r--src/com/android/deskclock/data/CityDAO.java20
-rw-r--r--src/com/android/deskclock/data/CityModel.java19
-rw-r--r--src/com/android/deskclock/provider/Alarm.java12
-rw-r--r--src/com/android/deskclock/provider/ClockDatabaseHelper.java5
-rwxr-xr-xsrc/com/android/deskclock/settings/DefaultAlarmToneDialog.java197
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/settings/SettingsActivity.java120
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/AddCityDialog.java223
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/CityAndTimeZoneLocator.java29
-rw-r--r--src/com/android/deskclock/worldclock/CitySelectionActivity.java252
-rwxr-xr-xsrc/com/android/deskclock/worldclock/TimeZoneSpinner.java182
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/db/DbCities.java4
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/db/DbCity.java4
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/db/DbCityDatabaseHelper.java4
-rwxr-xr-x[-rw-r--r--]src/com/android/deskclock/worldclock/db/DbCityProvider.java7
51 files changed, 1429 insertions, 491 deletions
diff --git a/res/drawable-hdpi/ic_actionbar_add.png b/res/drawable-hdpi/ic_actionbar_add.png
new file mode 100755
index 000000000..e051e8c19
--- /dev/null
+++ b/res/drawable-hdpi/ic_actionbar_add.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_gps_disabled.png b/res/drawable-hdpi/ic_gps_disabled.png
index fa0ab79d1..3c055e243 100644..100755
--- a/res/drawable-hdpi/ic_gps_disabled.png
+++ b/res/drawable-hdpi/ic_gps_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_gps_off.png b/res/drawable-hdpi/ic_gps_off.png
deleted file mode 100644
index 1d123c481..000000000
--- a/res/drawable-hdpi/ic_gps_off.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_gps_on.png b/res/drawable-hdpi/ic_gps_on.png
index 5138b70a1..6dbfa43d1 100644..100755
--- a/res/drawable-hdpi/ic_gps_on.png
+++ b/res/drawable-hdpi/ic_gps_on.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_actionbar_add.png b/res/drawable-mdpi/ic_actionbar_add.png
new file mode 100755
index 000000000..a5cec3ec2
--- /dev/null
+++ b/res/drawable-mdpi/ic_actionbar_add.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_gps_disabled.png b/res/drawable-mdpi/ic_gps_disabled.png
index df16865c9..072df31d7 100644..100755
--- a/res/drawable-mdpi/ic_gps_disabled.png
+++ b/res/drawable-mdpi/ic_gps_disabled.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_gps_off.png b/res/drawable-mdpi/ic_gps_off.png
deleted file mode 100644
index beb87734d..000000000
--- a/res/drawable-mdpi/ic_gps_off.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_gps_on.png b/res/drawable-mdpi/ic_gps_on.png
index 9e98ad9ed..6e258e081 100644..100755
--- a/res/drawable-mdpi/ic_gps_on.png
+++ b/res/drawable-mdpi/ic_gps_on.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_actionbar_add.png b/res/drawable-xhdpi/ic_actionbar_add.png
new file mode 100755
index 000000000..667e1fc1f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_actionbar_add.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_gps_disabled.png b/res/drawable-xhdpi/ic_gps_disabled.png
index fe612c4fd..27fb3e343 100644..100755
--- a/res/drawable-xhdpi/ic_gps_disabled.png
+++ b/res/drawable-xhdpi/ic_gps_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_gps_off.png b/res/drawable-xhdpi/ic_gps_off.png
deleted file mode 100644
index e34aecdbd..000000000
--- a/res/drawable-xhdpi/ic_gps_off.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_gps_on.png b/res/drawable-xhdpi/ic_gps_on.png
index d1d97685d..49202a572 100644..100755
--- a/res/drawable-xhdpi/ic_gps_on.png
+++ b/res/drawable-xhdpi/ic_gps_on.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_actionbar_add.png b/res/drawable-xxhdpi/ic_actionbar_add.png
new file mode 100755
index 000000000..55ddb4ba0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_actionbar_add.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_gps_disabled.png b/res/drawable-xxhdpi/ic_gps_disabled.png
new file mode 100755
index 000000000..4e37f0010
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_gps_disabled.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_gps_on.png b/res/drawable-xxhdpi/ic_gps_on.png
new file mode 100755
index 000000000..d6c326f59
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_gps_on.png
Binary files differ
diff --git a/res/drawable/holo_selector_nonfocusable.xml b/res/drawable/holo_selector_nonfocusable.xml
index c0ec9d5da..604eb910e 100644..100755
--- a/res/drawable/holo_selector_nonfocusable.xml
+++ b/res/drawable/holo_selector_nonfocusable.xml
@@ -14,14 +14,8 @@
** See the License for the specific language governing permissions and
** limitations under the License.
-->
-
<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_shortAnimTime">
-
- <item
- android:drawable="@android:color/holo_blue_dark"
- android:state_pressed="true"/>
- <item
- android:drawable="@android:color/transparent"/>
-
+ android:exitFadeDuration="@android:integer/config_shortAnimTime">
+ <item android:drawable="@android:color/holo_blue_dark" android:state_pressed="true"/>
+ <item android:drawable="@android:color/transparent"/>
</selector> \ No newline at end of file
diff --git a/res/drawable/ic_gps.xml b/res/drawable/ic_gps.xml
index 9f6ead003..0d81791da 100644..100755
--- a/res/drawable/ic_gps.xml
+++ b/res/drawable/ic_gps.xml
@@ -13,8 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_gps_disabled" android:state_enabled="false"/>
- <item android:drawable="@drawable/ic_gps_on"/>
+ <item android:drawable="@drawable/ic_gps_disabled" android:state_enabled="false"/>
+ <item android:drawable="@drawable/ic_gps_on"/>
</selector> \ No newline at end of file
diff --git a/res/drawable/ic_gps_anim.xml b/res/drawable/ic_gps_anim.xml
index d85d3559e..ac8c28794 100644..100755
--- a/res/drawable/ic_gps_anim.xml
+++ b/res/drawable/ic_gps_anim.xml
@@ -15,6 +15,6 @@
-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
- <item android:drawable="@drawable/ic_gps_off" android:duration="500" />
+ <item android:drawable="@drawable/ic_gps_disabled" android:duration="500" />
<item android:drawable="@drawable/ic_gps_on" android:duration="500" />
</animation-list> \ No newline at end of file
diff --git a/res/layout/city_add.xml b/res/layout/city_add.xml
index 9521fcb81..731945ac5 100644..100755
--- a/res/layout/city_add.xml
+++ b/res/layout/city_add.xml
@@ -13,64 +13,69 @@
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="wrap_content"
+ android:orientation="vertical"
android:paddingLeft="8dip"
- android:paddingRight="8dip"
- android:orientation="vertical">
+ android:paddingRight="8dip" >
<TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/cities_add_city_city"
- android:layout_marginTop="16dp"/>
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:paddingLeft="16dp"
+ android:text="@string/cities_add_city_city" />
<RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
- <EditText
- android:id="@+id/add_city_name"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:imeOptions="actionDone|flagNoFullscreen"
- android:scrollHorizontally="true"
- android:selectAllOnFocus="true"
- android:paddingLeft="48dp"
- android:inputType="textNoSuggestions">
- <requestFocus />
- </EditText>
+ <EditText
+ android:id="@+id/add_city_name"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_centerHorizontal="true"
+ android:layout_marginLeft="24dp"
+ android:imeOptions="actionDone|flagNoFullscreen"
+ android:inputType="textNoSuggestions"
+ android:maxLength="255"
+ android:paddingLeft="32dp"
+ android:scrollHorizontally="true"
+ android:selectAllOnFocus="true" >
- <ImageButton
- android:id="@+id/add_city_gps"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:contentDescription="@string/cities_add_city_gps_cd"
- android:src="@drawable/ic_gps"
- android:background="@drawable/holo_selector_nonfocusable"
- android:scaleType="fitCenter"
- android:layout_margin="5dp"
- android:layout_alignLeft="@id/add_city_name"
- android:layout_alignTop="@id/add_city_name"
- android:layout_alignBottom="@id/add_city_name" />
+ <requestFocus />
+ </EditText>
+ <ImageButton
+ android:id="@+id/add_city_gps"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_alignBottom="@id/add_city_name"
+ android:layout_alignTop="@id/add_city_name"
+ android:layout_margin="8dp"
+ android:background="@drawable/holo_selector_nonfocusable"
+ android:contentDescription="@string/cities_add_city_gps_cd"
+ android:gravity="center"
+ android:src="@drawable/ic_gps" />
</RelativeLayout>
<TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/cities_add_city_timezone"
- android:layout_marginTop="16dp"/>
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:paddingLeft="16dp"
+ android:text="@string/cities_add_city_timezone" />
- <Spinner
- android:id="@+id/add_city_tz"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="left|center_vertical"
- android:spinnerMode="dropdown"
- android:layout_marginBottom="16dp" />
+ <com.android.deskclock.worldclock.TimeZoneSpinner
+ android:id="@+id/add_city_tz"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:gravity="left|center_vertical"
+ android:paddingTop="5dp"
+ android:spinnerMode="dropdown" />
</LinearLayout> \ No newline at end of file
diff --git a/res/layout/time_zone_list.xml b/res/layout/time_zone_list.xml
new file mode 100755
index 000000000..5bc332c65
--- /dev/null
+++ b/res/layout/time_zone_list.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tz_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <ListView
+ android:id="@+id/tz_list"
+ android:layout_width="match_parent"
+ android:layout_height="336dp"
+ android:paddingLeft="14dp"
+ android:paddingRight="14dp" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/time_zone_list_item.xml b/res/layout/time_zone_list_item.xml
new file mode 100755
index 000000000..9e6e1b5b0
--- /dev/null
+++ b/res/layout/time_zone_list_item.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:id="@+id/tz_ll"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@android:id/text1"
+ style="?android:attr/spinnerItemStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:ellipsize="marquee"
+ android:gravity="left|center_vertical"
+ android:singleLine="true"
+ android:textAlignment="inherit" />
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/menu/desk_clock_menu.xml b/res/menu/desk_clock_menu.xml
index 1e54ed4b9..17269c527 100644
--- a/res/menu/desk_clock_menu.xml
+++ b/res/menu/desk_clock_menu.xml
@@ -28,8 +28,9 @@
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_item_add"
android:title="@string/menu_item_add"
- android:icon="@drawable/ic_menu_add"
- android:showAsAction="ifRoom|withText"/>
+ android:icon="@drawable/ic_actionbar_add"
+ app:showAsAction="always"
+ android:orderInCategory="2"/>
<item
android:id="@+id/menu_item_sort"
android:title="@string/menu_item_sort_by_gmt_offset"
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 0e590390c..ebe1c4fdc 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -38,6 +38,10 @@
<string name="default_timer_ringtone_title" msgid="1370799536406862317">"计时结束"</string>
<string name="silent_timer_ringtone_title" msgid="7588723137323327647">"静音"</string>
<string name="ringtone" msgid="9110746249688559579">"铃声"</string>
+ <string name="default_alarm_tone_title">默认闹钟铃声</string>
+ <string name="cities_add_city_title">加城市</string>
+ <string name="cities_add_city_city">城市:</string>
+ <string name="cities_add_city_timezone">时区:</string>
<string name="time" msgid="8067216534232296518">"时间"</string>
<string name="alarm_tomorrow" msgid="131356848787643420">"明天"</string>
<string name="alarm_today" msgid="7873594221106531654">"今天"</string>
@@ -359,6 +363,11 @@
<string name="collapse_alarm" msgid="3561772046433483980">"折叠闹钟"</string>
<string name="alarm_undo" msgid="5710042601177655254">"撤消"</string>
<string name="alarm_deleted" msgid="6131529309389084785">"闹钟已删除"</string>
+ <string name="alarm_select">选择铃声</string>
+ <string name="alarm_select_ringtone">铃声</string>
+ <string name="alarm_select_external">音乐</string>
+ <string name="alarm_select_ok">确定</string>
+ <string name="alarm_select_cancel">取消</string>
<string name="slash" msgid="2077577763821006919">"/"</string>
<string name="world_day_of_week_label" msgid="5911196322328341288">"/ <xliff:g id="LABEL">%s</xliff:g>"</string>
<string name="next_alarm_description" msgid="2650244835760747046">"下次闹钟时间:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -405,4 +414,12 @@
<string name="pick_alarm_to_dismiss" msgid="5408769235866082896">"请选择要关闭的闹钟"</string>
<string name="no_firing_alarms" msgid="4986161963178722289">"目前没有正在响铃的闹钟"</string>
<string name="alarm_is_snoozed" msgid="7044644119744928846">"<xliff:g id="ALARM_TIME">%s</xliff:g> 的闹钟已延后 10 分钟"</string>
+ <string name="flip_action_title">翻转行为</string>
+ <string name="shake_action_title">摇动行为</string>
+ <string name="shake_action_summary">摇动设备将<xliff:g id="action">%s</xliff:g></string>
+ <string name="flip_action_summary">翻转设备将<xliff:g id="action">%s</xliff:g></string>
+ <!-- Summary texts for shake and flip actions -->
+ <string name="action_summary_snooze">暂停闹铃</string>
+ <string name="action_summary_dismiss">停止闹铃</string>
+ <string name="action_summary_do_nothing">不产生任何作用</string>
</resources>
diff --git a/res/values/array.xml b/res/values/array.xml
index 2898e15fa..511f10b72 100644
--- a/res/values/array.xml
+++ b/res/values/array.xml
@@ -954,4 +954,9 @@
<item>C299</item>
<item>C300</item>
</string-array>
+ <string-array name="action_summary_entries" translatable="false">
+ <item>@string/action_summary_snooze</item>
+ <item>@string/action_summary_dismiss</item>
+ <item>@string/action_summary_do_nothing</item>
+ </string-array>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c1b5eaccc..1ca6960c7 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -39,6 +39,7 @@
<color name="color_accent">#DA4336</color>
<color name="hairline">#28ffffff</color>
<color name="bright_foreground_light_disabled">#80000000</color>
+ <color name="dialog_positive_button_disable">#4CDA4336</color>
<color name="clock_white">#ffffff</color>
<color name="clock_gray">#B3ffffff</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 89a417744..7e18ab426 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -28,6 +28,7 @@
<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>
+ <bool name="config_delayalarm">false</bool>
<bool name="config_ring_alarm_force">false</bool>
<bool name="config_silent_during_call">false</bool>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ad7c46930..1e2f63e33 100644..100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -364,6 +364,8 @@
<!-- Title of the setting to change hardware button behavior. This string
should be changed for each piece of hardware. [CHAR LIMIT=20] -->
<string name="volume_button_setting_title">Volume buttons</string>
+ <!-- Title of the setting default alarm tone -->
+ <string name="default_alarm_tone_title">Default alarm tone</string>
<!-- Dialog title of the volume and power setting. -->
<string name="volume_button_dialog_title">Button effect</string>
@@ -438,28 +440,30 @@
<string name="menu_item_settings">Settings</string>
<!-- Menu item on most screens to get to the help information -->
<string name="menu_item_help">Help</string>
+ <!-- Menu item on clock screen to add world city. -->
+ <string name="menu_item_add">Add</string>
+
<!-- Menu item on clock screen to enter night mode. -->
<string name="menu_item_night_mode">Night mode</string>
<!-- Menu item on Cities screen to sort by GMT offset -->
<string name="menu_item_sort_by_gmt_offset">Sort by time</string>
<!-- Menu item on Cities screen to sort by alphabetical order -->
<string name="menu_item_sort_by_name">Sort by name</string>
-
- <!-- User-defined cities -->
- <string name="menu_item_add">Add</string>
+ <string name="cities_add_gps_no_results">GPS query returns no location results</string>
+ <string name="cities_add_gps_not_available">GPS not available</string>
+ <string name="cities_add_searching">Searching\u2026</string>
<string name="cities_add_city_title">Add city</string>
- <string name="cities_add_city_city">City:</string>
- <string name="cities_add_city_timezone">Timezone:</string>
<string name="cities_add_city_gps_cd">Tap to localize your current city</string>
<string name="cities_add_loading">Loading\u2026</string>
- <string name="cities_add_searching">Searching\u2026</string>
- <string name="cities_add_gps_no_results">GPS query returns no location results</string>
- <string name="cities_add_gps_not_available">GPS not available</string>
+ <string name="cities_add_city_city">City:</string>
+ <string name="cities_add_city_timezone">Timezone:</string>
<string name="cities_add_already_exists">The city already exists in the database</string>
<string name="cities_add_city_failed">Can\'t create the city</string>
- <string name="cities_delete_city_title">Delete city</string>
- <string name="cities_delete_city_msg">Do you want to delete <xliff:g id="city">%s</xliff:g>?</string>
<string name="cities_delete_city_failed">Can\'t delete the city</string>
+ <string name="cities_delete_city_msg">Do you want to delete
+ <xliff:g id="city">%s</xliff:g>?
+ </string>
+ <string name="cities_delete_city_title">Delete city</string>
<!-- Label for selected cities in Cities list view -->
<string name="selected_cities_label">Selected Cities</string>
@@ -877,6 +881,16 @@
<string name="alarm_undo">undo</string>
<!-- Toast content when an alarm was deleted -->
<string name="alarm_deleted">Alarm deleted</string>
+ <!-- Select the source of the alarm -->
+ <string name="alarm_select">Select Alarm</string>
+ <!-- Select the ringtone as alarm -->
+ <string name="alarm_select_ringtone">Ringtone</string>
+ <!-- Select the alarm from external device -->
+ <string name="alarm_select_external">Music</string>
+ <!-- Ok for selection -->
+ <string name="alarm_select_ok">OK</string>
+ <!-- Cancel for selection -->
+ <string name="alarm_select_cancel">Cancel</string>
<!-- slash between date and next alarm in the clock -->
<string name="slash"> / </string>
<!-- slash between date and next alarm in the clock -->
@@ -1122,6 +1136,26 @@
[CHAR LIMIT=NONE]
-->
<string name="alarm_is_snoozed"><xliff:g id="alarm_time" example="14:20">%s</xliff:g> alarm snoozed for 10 minutes</string>
+ <!-- Setting title for the flip action setting. -->
+ <string name="flip_action_title">Flip action</string>
+
+ <!-- Setting summary for the flip action setting. -->
+ <string name="flip_action_summary" product="default">Flipping the phone down will
+ <xliff:g id="action">%s</xliff:g>
+ </string>
+
+ <!-- Setting title for the shake action setting. -->
+ <string name="shake_action_title">Shake action</string>
+
+ <!-- Setting summary for the shake action setting. -->
+ <string name="shake_action_summary" product="default">Shaking the phone will
+ <xliff:g id="action">%s</xliff:g>
+ </string>
+
+ <!-- Summary texts for shake and flip actions -->
+ <string name="action_summary_snooze">snooze the alarm</string>
+ <string name="action_summary_dismiss">dismiss the alarm</string>
+ <string name="action_summary_do_nothing">do nothing</string>
</resources>
diff --git a/res/xml/backup_scheme.xml b/res/xml/backup_scheme.xml
index 36ee3e822..08c9a0b1a 100644
--- a/res/xml/backup_scheme.xml
+++ b/res/xml/backup_scheme.xml
@@ -17,4 +17,8 @@
<full-backup-content>
<include domain="database" path="alarms.db" />
<include domain="sharedpref" path="com.android.deskclock_preferences.xml" />
+ <include domain="database" path="cities.db" />
+ <include domain="sharedpref" path="ce_shared_preferences.xml" />
+ <include domain="sharedpref" path="de_shared_preferences.xml" />
+
</full-backup-content> \ No newline at end of file
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
index 405ab4ae9..06d33b2cb 100644..100755
--- a/res/xml/settings.xml
+++ b/res/xml/settings.xml
@@ -47,8 +47,8 @@
</PreferenceCategory>
<PreferenceCategory
- android:title="@string/alarm_settings">
-
+ android:title="@string/alarm_settings"
+ android:key="key_alarm_settings">
<ListPreference
android:key="auto_silence"
android:title="@string/auto_silence_title"
@@ -79,21 +79,24 @@
android:entryValues="@array/volume_button_setting_values"
android:defaultValue="0" />
+ <com.android.deskclock.settings.DefaultAlarmToneDialog
+ android:key="default_alarm_tone"
+ android:title="@string/default_alarm_tone_title" />
+
<ListPreference
+ android:defaultValue="0"
+ android:dialogTitle="@string/flip_action_title"
+ android:entries="@array/volume_button_setting_entries"
+ android:entryValues="@array/volume_button_setting_values"
android:key="flip_action"
- android:title="@string/flip_action_title"
- android:dialogTitle="@string/flip_action_dialog_title"
- android:entries="@array/action_summary_entries"
- android:entryValues="@array/action_summary_values"
- android:defaultValue="0" />
-
+ android:title="@string/flip_action_title" />
<ListPreference
+ android:defaultValue="0"
+ android:dialogTitle="@string/shake_action_title"
+ android:entries="@array/volume_button_setting_entries"
+ android:entryValues="@array/volume_button_setting_values"
android:key="shake_action"
- android:title="@string/shake_action_title"
- android:dialogTitle="@string/shake_action_dialog_title"
- android:entries="@array/action_summary_entries"
- android:entryValues="@array/action_summary_values"
- android:defaultValue="0"/>
+ android:title="@string/shake_action_title" />
<ListPreference
android:key="week_start"
android:title="@string/week_start_title"
diff --git a/src/com/android/deskclock/AlarmClockFragment.java b/src/com/android/deskclock/AlarmClockFragment.java
index d443ba5a1..ac571debe 100644
--- a/src/com/android/deskclock/AlarmClockFragment.java
+++ b/src/com/android/deskclock/AlarmClockFragment.java
@@ -16,14 +16,20 @@
package com.android.deskclock;
+import android.Manifest;
import android.app.Activity;
import android.app.LoaderManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.Loader;
import android.database.Cursor;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
+import android.provider.Settings;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -39,6 +45,7 @@ import com.android.deskclock.alarms.TimePickerCompat;
import com.android.deskclock.alarms.dataadapter.AlarmTimeAdapter;
import com.android.deskclock.data.DataModel;
import com.android.deskclock.provider.Alarm;
+import com.android.deskclock.settings.DefaultAlarmToneDialog;
import com.android.deskclock.widget.EmptyViewController;
import com.android.deskclock.widget.toast.SnackbarManager;
import com.android.deskclock.widget.toast.ToastManager;
@@ -57,6 +64,21 @@ public final class AlarmClockFragment extends DeskClockFragment implements
// 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";
+ public static final String SEL_AUDIO_SRC = "audio/*";
+ public static final int SEL_SRC_RINGTONE = 0;
+ public static final int SEL_SRC_EXTERNAL = 1;
+ //extend request index is from 10 start
+ public static final int REQUEST_CODE_RINGTONE = 10;
+ public static final int REQUEST_CODE_PERMISSIONS = 11;
+ public static final int REQUEST_CODE_EXTERN_AUDIO = 12;
+
+ //QC hoffc added begin feature6
+ private static final String QUERY_URI = "content://com.android.deskclock/alarms";
+ private String old_default_ringtone_uri;
+ private String new_default_ringtone_Uri;
+ private RefreshDefaultRingtoneBroadcastReceiver mReceiver;
+ //QC hoffc added end
+
// Views
private ViewGroup mMainLayout;
private RecyclerView mRecyclerView;
@@ -81,6 +103,11 @@ public final class AlarmClockFragment extends DeskClockFragment implements
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
mCursorLoader = getLoaderManager().initLoader(0, null, this);
+
+ mReceiver = new RefreshDefaultRingtoneBroadcastReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(DefaultAlarmToneDialog.REFRESH_DEFAULT_RINGTONE_ACTION);
+ getActivity().registerReceiver(mReceiver, filter);
}
@Override
@@ -156,6 +183,8 @@ public final class AlarmClockFragment extends DeskClockFragment implements
public void onDestroy() {
super.onDestroy();
ToastManager.cancelToast();
+
+ getActivity().unregisterReceiver(mReceiver);
}
@Override
@@ -227,15 +256,22 @@ public final class AlarmClockFragment extends DeskClockFragment implements
switch (requestCode) {
case R.id.request_code_ringtone:
+ case REQUEST_CODE_RINGTONE:
+ case REQUEST_CODE_EXTERN_AUDIO:
// Extract the selected ringtone uri.
- Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+
+ Uri uri = null;
+ if (requestCode == REQUEST_CODE_EXTERN_AUDIO) {
+ uri = data.getData();
+ } else {
+ uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ }
+ LogUtils.d(LogUtils.LOGTAG, "AlarmClockFragment:onActivityResult: uri = " + 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) {
@@ -247,6 +283,13 @@ public final class AlarmClockFragment extends DeskClockFragment implements
// Save the change to alarm.
mAlarmUpdateHandler.asyncUpdateAlarm(alarm, false /* popToast */,
true /* minorUpdate */);
+
+ // If the user chose an external ringtone and has not yet granted the permission to read
+ // external storage, ask them for that permission now.
+ if (!AlarmUtils.hasPermissionToDisplayRingtoneTitle(getActivity(), uri)) {
+ final String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE};
+ requestPermissions(perms, REQUEST_CODE_PERMISSIONS);
+ }
break;
default:
LogUtils.w("Unhandled request code in onActivityResult: " + requestCode);
@@ -289,4 +332,61 @@ public final class AlarmClockFragment extends DeskClockFragment implements
TimePickerCompat.showTimeEditDialog(this, null /* alarm */,
DateFormat.is24HourFormat(getActivity()));
}
+
+ private class RefreshDefaultRingtoneBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ old_default_ringtone_uri = intent
+ .getStringExtra(DefaultAlarmToneDialog.OLD_RING_TONE_URI_STRING);
+ new_default_ringtone_Uri = intent
+ .getStringExtra(DefaultAlarmToneDialog.NEW_RING_TONE_URI_STRING);
+
+ LogUtils.d(LogUtils.LOGTAG, "old_default_ringtone_uri = " + old_default_ringtone_uri
+ + " new_default_ringtone_Uri = " + new_default_ringtone_Uri);
+
+ updateAlarmRingTone(new_default_ringtone_Uri, old_default_ringtone_uri);
+ updateAlarmRingTone(new_default_ringtone_Uri, Settings.System.DEFAULT_ALARM_ALERT_URI.toString());
+
+ // Update the default ringtone for future new alarms.
+ DataModel.getDataModel().setDefaultAlarmRingtoneUri(Uri.parse(new_default_ringtone_Uri));
+
+ }
+ }
+
+ private void updateAlarmRingTone(String newRingtone, String oldRingtone) {
+ Context accessContext = getActivity().getApplicationContext();
+ ContentResolver cr = accessContext.getContentResolver();
+
+ String selection = "ringtone = ?";
+ String[] selectionArgs;
+
+ if(oldRingtone != null
+ && !oldRingtone.equals(Settings.System.DEFAULT_ALARM_ALERT_URI.toString())) {
+ selectionArgs = new String[] {oldRingtone};
+ } else {
+ selectionArgs = new String[] {Settings.System.DEFAULT_ALARM_ALERT_URI.toString()};
+ }
+
+ LogUtils.d(LogUtils.LOGTAG, "updateAlarmRingTone: selectionArgs = " + selectionArgs[0]);
+
+ Cursor cursor = cr.query(
+ Uri.parse(QUERY_URI),
+ new String[] { "*" }, selection, selectionArgs, null);
+
+ Alarm a = null;
+ if (cursor != null && cursor.getCount() > 0) {
+ LogUtils.d(LogUtils.LOGTAG, "updateAlarmRingTone cursor.getCount() = " + cursor.getCount());
+ while (cursor.moveToNext()) {
+ a = new Alarm(cursor, Uri.parse(newRingtone));
+ LogUtils.d(LogUtils.LOGTAG, "The update alarm is " + a);
+ mAlarmUpdateHandler.asyncUpdateAlarm(a, false /* popToast */,
+ true /* minorUpdate */);
+ a = null;
+ }
+ }
+
+ if (cursor != null || cursor.getCount() == 0) {
+ cursor.close();
+ }
+ }
}
diff --git a/src/com/android/deskclock/AlarmUtils.java b/src/com/android/deskclock/AlarmUtils.java
index 5f91a0066..4e3f1e2c6 100644
--- a/src/com/android/deskclock/AlarmUtils.java
+++ b/src/com/android/deskclock/AlarmUtils.java
@@ -16,7 +16,12 @@
package com.android.deskclock;
+import android.Manifest;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.design.widget.Snackbar;
import android.text.format.DateFormat;
@@ -24,6 +29,7 @@ import android.text.format.DateUtils;
import android.view.View;
import android.widget.Toast;
+import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
import com.android.deskclock.widget.toast.SnackbarManager;
import com.android.deskclock.widget.toast.ToastManager;
@@ -101,4 +107,34 @@ public class AlarmUtils {
SnackbarManager.show(Snackbar.make(snackbarAnchor, text, Snackbar.LENGTH_SHORT));
snackbarAnchor.announceForAccessibility(text);
}
+
+ /**
+ * @return {@code true} iff the user has granted permission to read the ringtone at the given
+ * uri or no permission is required to read the ringtone
+ */
+ public static boolean hasPermissionToDisplayRingtoneTitle(Context context, Uri ringtoneUri) {
+ final PackageManager pm = context.getPackageManager();
+ final String packageName = context.getPackageName();
+
+ // If the default alarm alert ringtone URI is given, resolve it to the actual URI.
+ if (Settings.System.DEFAULT_ALARM_ALERT_URI.equals(ringtoneUri)) {
+ ringtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context,
+ RingtoneManager.TYPE_ALARM);
+ }
+
+ // If no ringtone is specified, return true.
+ if (ringtoneUri == null || ringtoneUri == Alarm.NO_RINGTONE_URI) {
+ return true;
+ }
+
+ // If the permission is already granted, return true.
+ if (pm.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ // If the ringtone is internal, return true;
+ // external ringtones require the permission to see their title
+ return ringtoneUri.toString().startsWith("content://media/internal/");
+ }
}
diff --git a/src/com/android/deskclock/AsyncRingtonePlayer.java b/src/com/android/deskclock/AsyncRingtonePlayer.java
index 3fb8230e4..1ce3cb485 100644
--- a/src/com/android/deskclock/AsyncRingtonePlayer.java
+++ b/src/com/android/deskclock/AsyncRingtonePlayer.java
@@ -63,7 +63,7 @@ public final class AsyncRingtonePlayer {
private PlaybackDelegate mPlaybackDelegate;
/** The context. */
- private static Context mContext;
+ private final Context mContext;
/** The key of the preference that controls the crescendo behavior when playing a ringtone. */
private final String mCrescendoPrefKey;
@@ -367,6 +367,7 @@ public final class AsyncRingtonePlayer {
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
}
+
player.setAudioStreamType(AudioManager.STREAM_ALARM);
player.setLooping(true);
player.prepare();
@@ -375,7 +376,7 @@ public final class AsyncRingtonePlayer {
player.start();
} else if (mContext.getResources().getBoolean(R.bool.config_ring_alarm_force)) {
mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM,
- mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM), 0);
+ mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM), 0);
player.setAudioStreamType(AudioManager.STREAM_ALARM);
player.setLooping(true);
player.prepare();
diff --git a/src/com/android/deskclock/Utils.java b/src/com/android/deskclock/Utils.java
index 251b59924..fe6c29d1f 100644..100755
--- a/src/com/android/deskclock/Utils.java
+++ b/src/com/android/deskclock/Utils.java
@@ -68,13 +68,6 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
-
-import com.android.deskclock.worldclock.db.DbCities;
-import com.android.deskclock.worldclock.db.DbCity;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
import java.util.Locale;
import java.util.TimeZone;
@@ -96,6 +89,9 @@ public class Utils {
*/
private static final int[] TEMP_ARRAY = new int[1];
+ public static final String DESKCLOCK_DE_SHARED_PREFERENCES = "de_sharedPreferences";
+ public static final String DESKCLOCK_CE_SHARED_PREFERENCES = "ce_sharedPreferences";
+
/**
* The background colors of the app - it changes throughout out the day to mimic the sky.
*/
@@ -707,43 +703,6 @@ public class Utils {
final ArraySet<E> arraySet = new ArraySet<>(collection.size());
arraySet.addAll(collection);
return arraySet;
-
- public static CityObj[] loadCitiesDataBase(Context c) {
- final Collator collator = Collator.getInstance();
- Resources r = c.getResources();
-
- // Get list of cities defined by the app (App-defined has the prefix C)
- // Read strings array of name,timezone, id
- // make sure the list are the same length
- String[] cities = r.getStringArray(R.array.cities_names);
- String[] timezones = r.getStringArray(R.array.cities_tz);
- String[] ids = r.getStringArray(R.array.cities_id);
- if (cities.length != timezones.length || ids.length != cities.length) {
- Log.wtf("City lists sizes are not the same, cannot use the data");
- return null;
- }
- List<CityObj> tempList = new ArrayList<CityObj>(cities.length);
- for (int i = 0; i < cities.length; i++) {
- tempList.add(new CityObj(cities[i], timezones[i], ids[i]));
- }
-
- // Get the list of user-defined cities (User-defined has the prefix UD)
- List<DbCity> dbcities = DbCities.getCities(c.getContentResolver());
- for (int i = 0; i < dbcities.size(); i++) {
- DbCity dbCity = dbcities.get(i);
- CityObj city = new CityObj(dbCity.name, dbCity.tz, "UD" + dbCity.id);
- city.mUserDefined = true;
- tempList.add(city);
- }
-
- // Sort alphabetically
- Collections.sort(tempList, new Comparator<CityObj> () {
- @Override
- public int compare(CityObj c1, CityObj c2) {
- return collator.compare(c1.mCityName, c2.mCityName);
- }
- });
- return tempList.toArray(new CityObj[tempList.size()]);
}
/**
@@ -767,4 +726,33 @@ public class Utils {
return PreferenceManager.getDefaultSharedPreferences(storageContext);
}
+
+ /**
+ * Return the desk clock_de shared preferences.
+ */
+ public static SharedPreferences getDESharedPreferences(Context context) {
+ final Context storageContext;
+ if (isNOrLater()) {
+ // All N devices have split storage areas, but we may need to
+ // migrate existing preferences into the new device protected
+ // storage area, which is where our data lives from now on.
+ final Context deviceContext = context.createDeviceProtectedStorageContext();
+ storageContext = deviceContext;
+ } else {
+ storageContext = context;
+ }
+
+ return storageContext.getSharedPreferences(DESKCLOCK_DE_SHARED_PREFERENCES,
+ Context.MODE_PRIVATE);
+ }
+
+
+ /**
+ * Return the desk clock_ce shared preferences.
+ */
+ public static SharedPreferences getCESharedPreferences(Context context) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences(
+ DESKCLOCK_CE_SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ return sharedPreferences;
+ }
}
diff --git a/src/com/android/deskclock/alarms/AlarmService.java b/src/com/android/deskclock/alarms/AlarmService.java
index 3f31c7f8b..b8f84d941 100644..100755
--- a/src/com/android/deskclock/alarms/AlarmService.java
+++ b/src/com/android/deskclock/alarms/AlarmService.java
@@ -18,32 +18,29 @@
*/
package com.android.deskclock.alarms;
-import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.Binder;
-import android.os.IBinder;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.preference.PreferenceManager;
+import android.os.Binder;
+import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import com.android.deskclock.AlarmAlertWakeLock;
import com.android.deskclock.LogUtils;
-
-import com.android.deskclock.SettingsActivity;
-import com.android.deskclock.provider.AlarmInstance;
import com.android.deskclock.R;
+import com.android.deskclock.Utils;
import com.android.deskclock.events.Events;
import com.android.deskclock.provider.AlarmInstance;
+import com.android.deskclock.settings.SettingsActivity;
/**
* This service is in charge of starting/stopping the alarm. It will bring up and manage the
@@ -75,36 +72,24 @@ public class AlarmService extends Service {
/** Private action used to stop an alarm with this service. */
public static final String STOP_ALARM_ACTION = "STOP_ALARM";
-
/** Binder given to AlarmActivity */
private final IBinder mBinder = new Binder();
- // default action for flip and shake
- private static final String DEFAULT_ACTION = "0";
-
- // constants for no action/snooze/dismiss
- private static final int ALARM_NO_ACTION = 0;
- private static final int ALARM_SNOOZE = 1;
- private static final int ALARM_DISMISS = 2;
-
- /**
- * Utility method to help start alarm properly. If alarm is already firing, it
- * will mark it as missed and start the new one.
- *
- * @param context application context
- * @param instance to trigger alarm
- */
- public static void startAlarm(Context context, AlarmInstance instance) {
- Intent intent = AlarmInstance.createIntent(context, AlarmService.class, instance.mId);
- intent.setAction(START_ALARM_ACTION);
- }
-
/** Whether the service is currently bound to AlarmActivity */
private boolean mIsBound = false;
/** Whether the receiver is currently registered */
private boolean mIsRegistered = false;
+ private SensorManager mSensorManager;
+ private int mFlipAction;
+ private int mShakeAction;
+ private static final int ALARM_NO_ACTION = 0;
+ private static final int ALARM_SNOOZE = 1;
+ private static final int ALARM_DISMISS = 2;
+ // default action for flip and shake
+ private static final String DEFAULT_ACTION = "0";
+
@Override
public IBinder onBind(Intent intent) {
mIsBound = true;
@@ -135,9 +120,6 @@ public class AlarmService extends Service {
private TelephonyManager mTelephonyManager;
private int mInitialCallState;
private AlarmInstance mCurrentAlarm = null;
- private SensorManager mSensorManager;
- private int mFlipAction;
- private int mShakeAction;
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
@@ -146,11 +128,15 @@ public class AlarmService extends Service {
// we register onCallStateChanged, we get the initial in-call state
// which kills the alarm. Check against the initial call state so
// we don't kill the alarm during a call.
+
if (AlarmService.this.getResources().getBoolean(R.bool.config_silent_during_call)
&& state != TelephonyManager.CALL_STATE_IDLE) {
- sendBroadcast(AlarmStateManager.createStateChangeIntent(AlarmService.this,
+ startService(AlarmStateManager.createStateChangeIntent(AlarmService.this,
"AlarmService", mCurrentAlarm, AlarmInstance.MISSED_STATE));
- } else if (state != TelephonyManager.CALL_STATE_IDLE && state != mInitialCallState) {
+ return;
+ }
+
+ if (state != TelephonyManager.CALL_STATE_IDLE && state != mInitialCallState) {
startService(AlarmStateManager.createStateChangeIntent(AlarmService.this,
"AlarmService", mCurrentAlarm, AlarmInstance.MISSED_STATE));
}
@@ -172,6 +158,7 @@ public class AlarmService extends Service {
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
AlarmKlaxon.start(this, mCurrentAlarm);
sendBroadcast(new Intent(ALARM_ALERT_ACTION));
+
attachListeners();
}
@@ -198,8 +185,9 @@ public class AlarmService extends Service {
AlarmNotifications.updateNotification(this, mCurrentAlarm);
}
- mCurrentAlarm = null;
detachListeners();
+
+ mCurrentAlarm = null;
AlarmAlertWakeLock.releaseCpuLock();
}
@@ -247,7 +235,7 @@ public class AlarmService extends Service {
mIsRegistered = true;
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ SharedPreferences prefs = Utils.getDefaultSharedPreferences(this);
mFlipAction = Integer.parseInt(prefs.getString(
SettingsActivity.KEY_FLIP_ACTION, DEFAULT_ACTION));
mShakeAction = Integer.parseInt(prefs.getString(
@@ -445,8 +433,8 @@ public class AlarmService extends Service {
break;
case ALARM_DISMISS:
// Setup Dismiss Action
- Intent dismissIntent = AlarmStateManager.createStateChangeIntent(this, "DISMISS_TAG",
- mCurrentAlarm, AlarmInstance.DISMISSED_STATE);
+ Intent dismissIntent = AlarmStateManager.createStateChangeIntent(this,
+ "DISMISS_TAG", mCurrentAlarm, AlarmInstance.DISMISSED_STATE);
sendBroadcast(dismissIntent);
break;
case ALARM_NO_ACTION:
@@ -454,5 +442,4 @@ public class AlarmService extends Service {
break;
}
}
-
}
diff --git a/src/com/android/deskclock/alarms/AlarmStateManager.java b/src/com/android/deskclock/alarms/AlarmStateManager.java
index d540f77a8..fbbcbc613 100644..100755
--- a/src/com/android/deskclock/alarms/AlarmStateManager.java
+++ b/src/com/android/deskclock/alarms/AlarmStateManager.java
@@ -30,6 +30,7 @@ import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.v4.app.NotificationManagerCompat;
+import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
import android.widget.Toast;
@@ -131,15 +132,15 @@ public final class AlarmStateManager extends BroadcastReceiver {
public static final String ALARM_SNOOZE_TAG = "SNOOZE_TAG";
public static final String ALARM_DELETE_TAG = "DELETE_TAG";
- // key to to retrieve pending alarm set
- public static final String ALARM_PENDING_ALARM_KEY = "pending.alarm.key";
-
// Intent category tag used when schedule state change intents in alarm manager.
private static final String ALARM_MANAGER_TAG = "ALARM_MANAGER";
// Buffer time in seconds to fire alarm instead of marking it missed.
public static final int ALARM_FIRE_BUFFER = 15;
+ // key to to retrieve pending alarm set
+ public static final String ALARM_PENDING_ALARM_KEY = "pending.alarm.key";
+
// A factory for the current time; can be mocked for testing purposes.
private static CurrentTimeFactory sCurrentTimeFactory;
@@ -168,16 +169,17 @@ public final class AlarmStateManager extends BroadcastReceiver {
}
public static void updateGlobalIntentId(Context context) {
- SharedPreferences prefs = Utils.getDefaultSharedPreferences(context);
+ SharedPreferences dePrefs = Utils.getDESharedPreferences(context);
// If there are any pending alarms, do not update the global id - pending alarms
// will be ignored by the receivers when the user tries to dismiss or snooze
- Set<String> alarms = prefs.getStringSet(AlarmStateManager.ALARM_PENDING_ALARM_KEY,
+ Set<String> alarms = dePrefs.getStringSet(AlarmStateManager.ALARM_PENDING_ALARM_KEY,
new HashSet<String>());
if (alarms.size() > 0) {
return;
}
+ SharedPreferences prefs = Utils.getDefaultSharedPreferences(context);
int globalId = prefs.getInt(ALARM_GLOBAL_ID_EXTRA, -1) + 1;
prefs.edit().putInt(ALARM_GLOBAL_ID_EXTRA, globalId).commit();
}
@@ -848,7 +850,7 @@ public final class AlarmStateManager extends BroadcastReceiver {
* @param instance to change state on
* @param state to change to
*/
- public static void setAlarmState(Context context, AlarmInstance instance, int state) {
+ private static void setAlarmState(Context context, AlarmInstance instance, int state) {
if (instance == null) {
LogUtils.e("Null alarm instance while setting state to %d", state);
return;
@@ -909,7 +911,49 @@ public final class AlarmStateManager extends BroadcastReceiver {
final String action = intent.getAction();
LogUtils.v("AlarmStateManager received intent " + intent);
if (CHANGE_STATE_ACTION.equals(action)) {
- handleChangeStateIntent(context, intent);
+ Uri uri = intent.getData();
+ AlarmInstance instance = AlarmInstance.getInstance(context.getContentResolver(),
+ AlarmInstance.getId(uri));
+ if (instance == null) {
+ LogUtils.e("Can not change state for unknown instance: " + uri);
+ return;
+ }
+
+ int globalId = getGlobalIntentId(context);
+ int intentId = intent.getIntExtra(ALARM_GLOBAL_ID_EXTRA, -1);
+ int alarmState = intent.getIntExtra(ALARM_STATE_EXTRA, -1);
+ if (intentId != globalId) {
+ LogUtils.i("IntentId: " + intentId + " GlobalId: " + globalId + " AlarmState: " +
+ alarmState);
+ // Allows dismiss/snooze requests to go through
+ if (!intent.hasCategory(ALARM_DISMISS_TAG) &&
+ !intent.hasCategory(ALARM_SNOOZE_TAG)) {
+ LogUtils.i("Ignoring old Intent");
+ return;
+ }
+ }
+
+ if (intent.getBooleanExtra(FROM_NOTIFICATION_EXTRA, false)) {
+ if (intent.hasCategory(ALARM_DISMISS_TAG)) {
+ Events.sendAlarmEvent(R.string.action_dismiss, R.string.label_notification);
+ } else if (intent.hasCategory(ALARM_SNOOZE_TAG)) {
+ Events.sendAlarmEvent(R.string.action_snooze, R.string.label_notification);
+ }
+ }
+
+ //If the phone is busy, add the alarm to a string set in shared preferenecs that will be
+ // cleared when the call is ended.
+ if (context.getResources().getBoolean(R.bool.config_delayalarm)) {
+ TelephonyManager mTelephonyManager = (TelephonyManager) context
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ if ((mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE)
+ && (alarmState == AlarmInstance.FIRED_STATE)) {
+ pendAlarm(context, uri, alarmState);
+ return;
+ }
+ }
+
+ setChangeAlarmState(context, instance, alarmState);
} else if (SHOW_AND_DISMISS_ALARM_ACTION.equals(action)) {
Uri uri = intent.getData();
AlarmInstance instance = AlarmInstance.getInstance(context.getContentResolver(),
@@ -935,76 +979,6 @@ public final class AlarmStateManager extends BroadcastReceiver {
}
}
- private static void handleChangeStateIntent(Context context, Intent intent) {
- Uri uri = intent.getData();
- AlarmInstance instance = AlarmInstance.getInstance(context.getContentResolver(),
- AlarmInstance.getId(uri));
- if (instance == null) {
- // Not a big deal, but it shouldn't happen
- LogUtils.e("Can not change state for unknown instance: " + uri);
- return;
- }
-
- int globalId = getGlobalIntentId(context);
- int intentId = intent.getIntExtra(ALARM_GLOBAL_ID_EXTRA, -1);
- int alarmState = intent.getIntExtra(ALARM_STATE_EXTRA, -1);
- if (intentId != globalId) {
- LogUtils.i("Ignoring old Intent. IntentId: " + intentId + " GlobalId: " + globalId +
- " AlarmState: " + alarmState);
- return;
- }
-
- // If the phone is busy, add the alarm to a string set in shared preferenecs that will be
- // cleared when the call is ended.
- if (context.getResources().getBoolean(R.bool.config_delayalarm)) {
- TelephonyManager mTelephonyManager = (TelephonyManager) context
- .getSystemService(Context.TELEPHONY_SERVICE);
- if ((mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE)
- && (alarmState == AlarmInstance.FIRED_STATE)) {
- pendAlarm(context, uri, alarmState);
- return;
- }
- }
-
- setChangeAlarmState(context, instance, alarmState);
- }
-
- public static void setChangeAlarmState(Context context, AlarmInstance instance,
- int alarmState) {
-
- if (alarmState >= 0) {
- setAlarmState(context, instance, alarmState);
- } else {
- // No need to register instance again when alarmState
- // equals POWER_OFF_ALARM_STATE. POWER_OFF_ALARM_STATE
- // is an invalid state for rtc power off alarm.
- if (alarmState == AlarmInstance.POWER_OFF_ALARM_STATE) {
- return;
- }
- registerInstance(context, instance, true);
- }
- }
-
- /**
- * Add the alarm to list of pending Alarms to be fired after the call is complete.
- */
- private static void pendAlarm(Context context, Uri uri, int alarmState) {
- LogUtils.v("Pending alarm: " + uri);
-
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- Set<String> alarms = sp.getStringSet(ALARM_PENDING_ALARM_KEY, new HashSet<String>());
-
- // Alarms are stored as "<uri>|<alarmState>"
- String alarm = uri.toString() + "|" + alarmState;
-
- HashSet<String> newSet = new HashSet<String>();
- newSet.addAll(alarms);
- newSet.add(alarm);
-
- sp.edit().putStringSet(ALARM_PENDING_ALARM_KEY, newSet).commit();
- }
-
-
/**
* Creates an intent that can be used to set an AlarmManager alarm to set the next alarm
* indicators.
@@ -1071,4 +1045,32 @@ public final class AlarmStateManager extends BroadcastReceiver {
}
}
}
+
+ /**
+ * Add the alarm to list of pending Alarms to be fired after the call is complete.
+ */
+ private static void pendAlarm(Context context, Uri uri, int alarmState) {
+ LogUtils.v("Pending alarm: " + uri);
+
+ SharedPreferences sp = Utils.getDESharedPreferences(context);
+ Set<String> alarms = sp.getStringSet(ALARM_PENDING_ALARM_KEY, new HashSet<String>());
+
+ // Alarms are stored as "<uri>|<alarmState>"
+ String alarm = uri.toString() + "|" + alarmState;
+
+ HashSet<String> newSet = new HashSet<String>();
+ newSet.addAll(alarms);
+ newSet.add(alarm);
+
+ sp.edit().putStringSet(ALARM_PENDING_ALARM_KEY, newSet).commit();
+ }
+
+ public static void setChangeAlarmState(Context context, AlarmInstance instance,
+ int alarmState) {
+ if (alarmState >= 0) {
+ setAlarmState(context, instance, alarmState);
+ } else {
+ registerInstance(context, instance, true);
+ }
+ }
}
diff --git a/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java b/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
index 524900381..0f898d766 100644
--- a/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
+++ b/src/com/android/deskclock/alarms/AlarmTimeClickHandler.java
@@ -16,9 +16,11 @@
package com.android.deskclock.alarms;
+import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
@@ -26,6 +28,7 @@ import android.os.Bundle;
import android.os.Vibrator;
import android.text.format.DateFormat;
+import com.android.deskclock.AlarmClockFragment;
import com.android.deskclock.LabelDialogFragment;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
@@ -43,6 +46,9 @@ public final class AlarmTimeClickHandler {
private static final String TAG = "AlarmTimeClickHandler";
private static final String KEY_PREVIOUS_DAY_MAP = "previousDayMap";
+ private int mSelectSource = AlarmClockFragment.SEL_SRC_RINGTONE;
+ private static final String KEY_SELECT_SOURCE = "selectedSource";
+
private final Fragment mFragment;
private final AlarmUpdateHandler mAlarmUpdateHandler;
private final ScrollHandler mScrollHandler;
@@ -75,6 +81,7 @@ public final class AlarmTimeClickHandler {
public void saveInstance(Bundle outState) {
outState.putBundle(KEY_PREVIOUS_DAY_MAP, mPreviousDaysOfWeekMap);
+ outState.putInt(KEY_SELECT_SOURCE, mSelectSource);
}
public void setAlarmEnabled(Alarm alarm, boolean newState) {
@@ -162,14 +169,7 @@ public final class AlarmTimeClickHandler {
}
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);
+ launchRingTonePicker(alarm);
}
public void onEditLabelClicked(Alarm alarm) {
@@ -203,4 +203,57 @@ public final class AlarmTimeClickHandler {
mSelectedAlarm = null;
}
}
+
+ private void launchRingTonePicker(Alarm alarm) {
+ mSelectedAlarm = alarm;
+ RingTonePickerDialogListener listener = new RingTonePickerDialogListener((AlarmClockFragment)mFragment);
+ new AlertDialog.Builder(mFragment.getActivity())
+ .setTitle(mFragment.getResources().getString(R.string.alarm_select))
+ .setItems(
+ new String[] {
+ mFragment.getResources().getString(
+ R.string.alarm_select_ringtone),
+ mFragment.getResources().getString(
+ R.string.alarm_select_external) },
+ listener).show();
+ }
+
+ private class RingTonePickerDialogListener implements DialogInterface.OnClickListener {
+ private AlarmClockFragment alarm;
+
+ public RingTonePickerDialogListener(AlarmClockFragment clock) {
+ alarm = clock;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case AlarmClockFragment.SEL_SRC_RINGTONE:
+ case AlarmClockFragment.SEL_SRC_EXTERNAL:
+ mSelectSource = which;
+ sendPickIntent();
+ break;
+ default:
+ dialog.dismiss();
+ break;
+ }
+ }
+ }
+
+ private void sendPickIntent() {
+ LogUtils.d(TAG, "sendPickIntent is called, mSelectSource = " + mSelectSource);
+ if (mSelectSource == AlarmClockFragment.SEL_SRC_RINGTONE) {
+ final Uri oldRingtone = Alarm.NO_RINGTONE_URI.equals(mSelectedAlarm.alert) ? null : mSelectedAlarm.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, AlarmClockFragment.REQUEST_CODE_RINGTONE);
+ } else {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, mSelectedAlarm.alert);
+ intent.setType(AlarmClockFragment.SEL_AUDIO_SRC);
+ mFragment.startActivityForResult(intent, AlarmClockFragment.REQUEST_CODE_EXTERN_AUDIO);
+ }
+ }
}
diff --git a/src/com/android/deskclock/alarms/PhoneStateReceiver.java b/src/com/android/deskclock/alarms/PhoneStateReceiver.java
index 2ddcfd3a4..2479e4a59 100644..100755
--- a/src/com/android/deskclock/alarms/PhoneStateReceiver.java
+++ b/src/com/android/deskclock/alarms/PhoneStateReceiver.java
@@ -9,6 +9,7 @@ import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.android.deskclock.LogUtils;
+import com.android.deskclock.Utils;
import com.android.deskclock.provider.AlarmInstance;
import java.util.HashSet;
@@ -30,7 +31,7 @@ public class PhoneStateReceiver extends BroadcastReceiver {
.getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
// New call state is idle, update state for any pending alarms
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences sp = Utils.getDESharedPreferences(context);
Set<String> alarms = sp.getStringSet(AlarmStateManager.ALARM_PENDING_ALARM_KEY,
new HashSet<String>());
if (alarms.size() <= 0) {
diff --git a/src/com/android/deskclock/data/CityDAO.java b/src/com/android/deskclock/data/CityDAO.java
index 544bc298d..fa37a92e5 100644
--- a/src/com/android/deskclock/data/CityDAO.java
+++ b/src/com/android/deskclock/data/CityDAO.java
@@ -24,8 +24,11 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
+import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
+import com.android.deskclock.worldclock.db.DbCities;
+import com.android.deskclock.worldclock.db.DbCity;
import java.util.ArrayList;
import java.util.Collection;
@@ -116,7 +119,10 @@ final class CityDAO {
throw new IllegalStateException(message);
}
- final Map<String, City> cities = new ArrayMap<>(ids.length);
+ //add the clock db data to all cities list
+ List<DbCity> dbCities = DbCities.getCities(context.getContentResolver());
+ final Map<String, City> cities = new ArrayMap<>(ids.length + dbCities.size());
+
for (int i = 0; i < ids.length; i++) {
final String id = ids[i];
if ("C0".equals(id)) {
@@ -124,6 +130,16 @@ final class CityDAO {
}
cities.put(id, createCity(id, names[i], timezones[i]));
}
+
+ //add the clock db data to all cities list
+ for (int i = 0; i < dbCities.size(); i++) {
+ DbCity dbCity = dbCities.get(i);
+ String formatName = dbCity.name.charAt(0) + "=" + dbCity.name;
+ LogUtils.d(LogUtils.LOGTAG, "getCities: formatName = " + formatName);
+ cities.put("UD" + dbCity.id, CityDAO.createCity("UD" + dbCity.id,
+ formatName, dbCity.tz));
+ }
+
return Collections.unmodifiableMap(cities);
}
@@ -135,7 +151,7 @@ final class CityDAO {
* @param timeZoneId identifies the timezone in which the city is located
*/
@VisibleForTesting
- static City createCity(String id, String formattedName, String timeZoneId) {
+ public static City createCity(String id, String formattedName, String timeZoneId) {
final String[] parts = formattedName.split("[=:]");
final String name = parts[1];
// Extract index string from input, use the first character of city name as index string
diff --git a/src/com/android/deskclock/data/CityModel.java b/src/com/android/deskclock/data/CityModel.java
index 535867299..472f7dc0c 100644
--- a/src/com/android/deskclock/data/CityModel.java
+++ b/src/com/android/deskclock/data/CityModel.java
@@ -24,10 +24,13 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.preference.PreferenceManager;
+import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import com.android.deskclock.data.DataModel.CitySort;
import com.android.deskclock.settings.SettingsActivity;
+import com.android.deskclock.worldclock.db.DbCities;
+import com.android.deskclock.worldclock.db.DbCity;
import java.util.ArrayList;
import java.util.Collection;
@@ -100,6 +103,17 @@ final class CityModel {
final List<City> allCities = new ArrayList<>(getCityMap().size());
allCities.addAll(selected);
allCities.addAll(getUnselectedCities());
+
+ //add the clock db data to all cities list
+ List<DbCity> dbCities = DbCities.getCities(mContext.getContentResolver());
+ for (int i = 0; i < dbCities.size(); i++) {
+ DbCity dbCity = dbCities.get(i);
+ String formatName = dbCity.name.charAt(0) + "=" + dbCity.name;
+ LogUtils.d(LogUtils.LOGTAG, "getCities: formatName = " + formatName);
+ allCities.add(CityDAO.createCity("UD" + dbCity.id,
+ formatName, dbCity.tz));
+ }
+
mAllCities = Collections.unmodifiableList(allCities);
}
@@ -219,10 +233,7 @@ final class CityModel {
}
private Map<String, City> getCityMap() {
- if (mCityMap == null) {
- mCityMap = CityDAO.getCities(mContext);
- }
-
+ mCityMap = CityDAO.getCities(mContext);
return mCityMap;
}
diff --git a/src/com/android/deskclock/provider/Alarm.java b/src/com/android/deskclock/provider/Alarm.java
index 7fac18b7d..c1e64dd4d 100644
--- a/src/com/android/deskclock/provider/Alarm.java
+++ b/src/com/android/deskclock/provider/Alarm.java
@@ -307,6 +307,18 @@ public final class Alarm implements Parcelable, ClockContract.AlarmsColumns {
deleteAfterUse = p.readInt() == 1;
}
+ public Alarm(Cursor c, Uri defaultRingtoneUri) {
+ id = c.getLong(ID_INDEX);
+ enabled = c.getInt(ENABLED_INDEX) == 1;
+ hour = c.getInt(HOUR_INDEX);
+ minutes = c.getInt(MINUTES_INDEX);
+ daysOfWeek = new DaysOfWeek(c.getInt(DAYS_OF_WEEK_INDEX));
+ vibrate = c.getInt(VIBRATE_INDEX) == 1;
+ label = c.getString(LABEL_INDEX);
+ deleteAfterUse = c.getInt(DELETE_AFTER_USE_INDEX) == 1;
+ alert = defaultRingtoneUri;
+ }
+
public String getLabelOrDefault(Context context) {
return label.isEmpty() ? context.getString(R.string.default_label) : label;
}
diff --git a/src/com/android/deskclock/provider/ClockDatabaseHelper.java b/src/com/android/deskclock/provider/ClockDatabaseHelper.java
index b75670d01..64f1df0fd 100644
--- a/src/com/android/deskclock/provider/ClockDatabaseHelper.java
+++ b/src/com/android/deskclock/provider/ClockDatabaseHelper.java
@@ -56,11 +56,12 @@ class ClockDatabaseHelper extends SQLiteOpenHelper {
*/
private static final int VERSION_8 = 8;
+ //Setting default alarm to system setting alarm_alert
// This creates a default alarm at 8:30 for every Mon,Tue,Wed,Thu,Fri
- private static final String DEFAULT_ALARM_1 = "(8, 30, 31, 0, 1, '', NULL, 0);";
+ private static final String DEFAULT_ALARM_1 = "(8, 30, 31, 0, 1, '', 'content://settings/system/alarm_alert', 0);";
// This creates a default alarm at 9:30 for every Sat,Sun
- private static final String DEFAULT_ALARM_2 = "(9, 00, 96, 0, 1, '', NULL, 0);";
+ private static final String DEFAULT_ALARM_2 = "(9, 00, 96, 0, 1, '', 'content://settings/system/alarm_alert', 0);";
// Database and table names
static final String DATABASE_NAME = "alarms.db";
diff --git a/src/com/android/deskclock/settings/DefaultAlarmToneDialog.java b/src/com/android/deskclock/settings/DefaultAlarmToneDialog.java
new file mode 100755
index 000000000..d2479d21d
--- /dev/null
+++ b/src/com/android/deskclock/settings/DefaultAlarmToneDialog.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.deskclock.settings;
+
+import com.android.deskclock.AlarmClockFragment;
+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.provider.Alarm;
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.DialogInterface.OnClickListener;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.preference.DialogPreference;
+import android.util.AttributeSet;
+
+public class DefaultAlarmToneDialog extends DialogPreference {
+ private int mSelectSource;
+ private String mRingtone;
+ private Boolean showDefaultRingtone;
+ private static Uri oldRingTone;
+ // set default of default_ring_tone
+ public static final String DEFAULT_RING_TONE_DEFAULT = "content://media/internal/audio/media/9";
+ // the key of default_ring_tone‘default from sharedpreference
+ public static final String DEFAULT_RING_TONE_URI_KEY = "defaultRingTone_uri";
+ // the key of defaultRingTone to show (set summary) from sharepredference
+ public static final String DEFAULT_RING_TONE_NAME_KEY = "defaultRingTone_name";
+ public static final String DEFAULT_RING_TONE_NAME = "Cesium";
+ public static final String OLD_RING_TONE_URI_STRING = "old_uri_toString";
+ public static final String NEW_RING_TONE_URI_STRING = "new_uri_toString";
+ public static final String REFRESH_DEFAULT_RINGTONE_ACTION =
+ "com.android.deskclock.action.REFRSH_DEFAULT_RING_TONE";
+ public static final String SETTING_SYSTEM_RINGTONE = "content://settings/system/ringtone";
+ public SharedPreferences sp;
+ public Context mcontext;
+
+ public DefaultAlarmToneDialog(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.mcontext = context;
+ sp = Utils.getCESharedPreferences(context);
+
+ if (sp.getString(DEFAULT_RING_TONE_NAME_KEY, null) == null) {
+ LogUtils.d(LogUtils.LOGTAG, "DefaultAlarmToneDialog: summary = null");
+ setSummary(DEFAULT_RING_TONE_NAME);
+ }
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ builder.setTitle(
+ mcontext.getResources().getString(R.string.alarm_select))
+ .setItems(
+ new String[] {
+ mcontext.getResources().getString(
+ R.string.alarm_select_ringtone),
+ mcontext.getResources().getString(
+ R.string.alarm_select_external) },
+ new OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ switch (which) {
+ case AlarmClockFragment.SEL_SRC_RINGTONE:
+ case AlarmClockFragment.SEL_SRC_EXTERNAL:
+ mSelectSource = which;
+ sendPickIntent(which);
+ break;
+ default:
+ dialog.dismiss();
+ break;
+ }
+ }
+ }).setPositiveButton(null, null)
+ .setNegativeButton(null, null).setCancelable(true);
+ }
+
+ private void sendPickIntent(int selectSource) {
+ SettingsActivity activity = (SettingsActivity) mcontext;
+ String defaultRingTone = sp.getString(DEFAULT_RING_TONE_URI_KEY, DEFAULT_RING_TONE_DEFAULT);
+ if ("".equalsIgnoreCase(defaultRingTone)) {
+ oldRingTone = null;
+ } else {
+ oldRingTone = Uri.parse(defaultRingTone);
+ }
+
+ LogUtils.d(LogUtils.LOGTAG, "defaultAlarmToneDialog sendPickIntent oldRingTone = " + oldRingTone);
+ if (selectSource == AlarmClockFragment.SEL_SRC_RINGTONE) {
+ 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);
+ activity.startActivityForResult(intent,
+ AlarmClockFragment.REQUEST_CODE_RINGTONE);
+ } else {
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI,
+ oldRingTone);
+ intent.setType(AlarmClockFragment.SEL_AUDIO_SRC);
+ activity.startActivityForResult(intent,
+ AlarmClockFragment.REQUEST_CODE_EXTERN_AUDIO);
+ }
+ }
+
+ public void saveRingtoneUri(Intent intent) {
+ Uri uri = getRingtoneUri(intent);
+ sp.edit().putString(DEFAULT_RING_TONE_URI_KEY, uri.toString()).apply();
+ String displayNameString = getRingtoneString(uri);
+ sp.edit().putString(DEFAULT_RING_TONE_NAME_KEY, displayNameString)
+ .apply();
+
+ LogUtils.d(LogUtils.LOGTAG, "saveRingtoneUri: uri = " + uri
+ + " displayNameString = " + displayNameString);
+
+ if(oldRingTone == null){
+ oldRingTone = Uri.parse("");
+ }
+
+ if (uri != oldRingTone) {
+ // sendBroadcast to refresh Alarm's ringtone which is default
+ sendRefreshBroadcast(uri);
+ }
+
+ if (uri.toString().equals(SETTING_SYSTEM_RINGTONE)) {
+ LogUtils.d(LogUtils.LOGTAG, "saveRingtoneUri: remove SP DEFAULT_RING_TONE_URI_KEY");
+ sp.edit().remove(DEFAULT_RING_TONE_URI_KEY).apply();
+ }
+ }
+
+ private void sendRefreshBroadcast(Uri uri) {
+ Intent uriIntent = new Intent();
+ uriIntent.putExtra(OLD_RING_TONE_URI_STRING, oldRingTone.toString());
+ uriIntent.putExtra(NEW_RING_TONE_URI_STRING, uri.toString());
+ uriIntent.setAction(REFRESH_DEFAULT_RINGTONE_ACTION);
+ mcontext.sendBroadcast(uriIntent);
+ }
+
+ private String getRingtoneString(Uri uri) {
+ if (Alarm.NO_RINGTONE_URI.equals(uri)) {
+ mRingtone = mcontext.getResources().getString(R.string.silent_ringtone_title);
+ } else {
+ mRingtone = DataModel.getDataModel().getAlarmRingtoneTitle(uri);
+ }
+ return mRingtone;
+ }
+
+ private Uri getRingtoneUri(Intent intent) {
+ Uri uri;
+ if (mSelectSource == AlarmClockFragment.SEL_SRC_RINGTONE) {
+ uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ } else {
+ uri = intent.getData();
+ }
+
+ if (uri == null) {
+ uri = Alarm.NO_RINGTONE_URI;
+ }
+ return uri;
+ }
+
+}
diff --git a/src/com/android/deskclock/settings/SettingsActivity.java b/src/com/android/deskclock/settings/SettingsActivity.java
index 82f4fa5dd..de306b2b2 100644..100755
--- a/src/com/android/deskclock/settings/SettingsActivity.java
+++ b/src/com/android/deskclock/settings/SettingsActivity.java
@@ -16,9 +16,11 @@
package com.android.deskclock.settings;
+import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorManager;
@@ -26,7 +28,10 @@ import android.media.AudioManager;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
+import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
import android.preference.RingtonePreference;
import android.preference.SwitchPreference;
import android.provider.Settings;
@@ -34,6 +39,8 @@ import android.text.format.DateUtils;
import android.view.Menu;
import android.view.MenuItem;
+import com.android.deskclock.AlarmClockFragment;
+import com.android.deskclock.AlarmUtils;
import com.android.deskclock.BaseActivity;
import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
@@ -67,11 +74,14 @@ public final class SettingsActivity extends BaseActivity {
public static final String KEY_VOLUME_BUTTONS = "volume_button_setting";
public static final String KEY_WEEK_START = "week_start";
- public static final String KEY_FLIP_ACTION = "flip_action";
- public static final String KEY_SHAKE_ACTION = "shake_action";
-
public static final String TIMEZONE_LOCALE = "tz_locale";
+ public static final String KEY_DEFAULT_ALARM_TONE = "default_alarm_tone";
+ private static DefaultAlarmToneDialog mdefaultAlarmTone;
+
+ public static final String KEY_ALARM_SETTINGS = "key_alarm_settings";
+ public static final String KEY_FLIP_ACTION = "flip_action";
+ public static final String KEY_SHAKE_ACTION = "shake_action";
public static final String DEFAULT_VOLUME_BEHAVIOR = "0";
public static final String VOLUME_BEHAVIOR_SNOOZE = "1";
@@ -115,6 +125,11 @@ public final class SettingsActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ //fix google native issue, cannot save and effect settingActivity's setting item
+ if(Utils.isNOrLater()) {
+ getPreferenceManager().setStorageDeviceProtected();
+ }
+
addPreferencesFromResource(R.xml.settings);
loadTimeZoneList();
}
@@ -176,12 +191,22 @@ public final class SettingsActivity extends BaseActivity {
timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
break;
case KEY_FLIP_ACTION:
- final ListPreference listPref = (ListPreference) pref;
- updateActionSummary(listPref, (String) newValue, R.string.flip_action_summary);
+ LogUtils.d(LogUtils.LOGTAG, "onPreferenceChange: flip");
+ final ListPreference flipPref = (ListPreference) pref;
+ int i = flipPref.findIndexOfValue((String) newValue);
+ flipPref.setSummary(getString(
+ R.string.flip_action_summary,
+ getResources().getStringArray(
+ R.array.action_summary_entries)[i]));
break;
case KEY_SHAKE_ACTION:
- final ListPreference listPref = (ListPreference) pref;
- updateActionSummary(listPref, (String) newValue, R.string.shake_action_summary);
+ LogUtils.d(LogUtils.LOGTAG, "onPreferenceChange: shake");
+ final ListPreference shakePref = (ListPreference) pref;
+ int ii = shakePref.findIndexOfValue((String) newValue);
+ shakePref.setSummary(getString(
+ R.string.shake_action_summary,
+ getResources().getStringArray(
+ R.array.action_summary_entries)[ii]));
break;
}
// Set result so DeskClock knows to refresh itself
@@ -189,12 +214,6 @@ public final class SettingsActivity extends BaseActivity {
return true;
}
- private void updateActionSummary(ListPreference listPref, String action, int summaryResId) {
- int i = Integer.parseInt(action);
- listPref.setSummary(getString(summaryResId,
- getResources().getStringArray(R.array.action_summary_entries)[i]));
- }
-
@Override
public boolean onPreferenceClick(Preference pref) {
final Activity activity = getActivity();
@@ -294,6 +313,15 @@ public final class SettingsActivity extends BaseActivity {
final Preference volumePref = findPreference(KEY_ALARM_VOLUME);
volumePref.setOnPreferenceClickListener(this);
+ mdefaultAlarmTone =
+ (DefaultAlarmToneDialog) findPreference(KEY_DEFAULT_ALARM_TONE);
+ SharedPreferences sharedPreferences = Utils.getCESharedPreferences(getContext());
+ LogUtils.d(LogUtils.LOGTAG, "refresh: summary = " + sharedPreferences.getString(
+ DefaultAlarmToneDialog.DEFAULT_RING_TONE_NAME_KEY,null));
+ mdefaultAlarmTone.setSummary(sharedPreferences.getString(
+ DefaultAlarmToneDialog.DEFAULT_RING_TONE_NAME_KEY,
+ DefaultAlarmToneDialog.DEFAULT_RING_TONE_NAME));
+
final SnoozeLengthDialog snoozePref =
(SnoozeLengthDialog) findPreference(KEY_ALARM_SNOOZE);
snoozePref.setSummary();
@@ -323,13 +351,46 @@ public final class SettingsActivity extends BaseActivity {
timerRingtonePref.setSummary(DataModel.getDataModel().getTimerRingtoneTitle());
timerRingtonePref.setOnPreferenceChangeListener(this);
- listPref = (ListPreference) findPreference(KEY_FLIP_ACTION);
- updateActionSummary(listPref, listPref.getValue(), R.string.flip_action_summary);
- listPref.setOnPreferenceChangeListener(this);
+ PreferenceCategory category = (PreferenceCategory) findPreference(
+ KEY_ALARM_SETTINGS);
+ SensorManager sensorManager = (SensorManager) getActivity()
+ .getSystemService(Context.SENSOR_SERVICE);
+ ListPreference flipPreference = (ListPreference) findPreference(KEY_FLIP_ACTION);
+ if (flipPreference != null) {
+ List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
+ if (sensorList.size() < 1) { // This will be true if no orientation sensor
+ flipPreference.setValue("0"); // Turn it off
+ if (category != null) {
+ LogUtils.d(LogUtils.LOGTAG, "filpPreference is removed");
+ category.removePreference(flipPreference);
+ }
+ } else {
+ int i = flipPreference.findIndexOfValue(flipPreference.getValue());
+ flipPreference.setSummary(getString(
+ R.string.flip_action_summary,
+ getResources().getStringArray(R.array.action_summary_entries)[i]));
+ flipPreference.setOnPreferenceChangeListener(this);
+ }
+ }
- listPref = (ListPreference) findPreference(KEY_SHAKE_ACTION);
- updateActionSummary(listPref, listPref.getValue(), R.string.shake_action_summary);
- listPref.setOnPreferenceChangeListener(this);
+ ListPreference shakePreference = (ListPreference) findPreference(KEY_SHAKE_ACTION);
+ if (shakePreference != null) {
+ List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
+ if (sensorList.size() < 1) { // This will be true if no accelerometer sensor
+ shakePreference.setValue("0"); // Turn it off
+ if (category != null) {
+ LogUtils.d(LogUtils.LOGTAG, "shakePreference is removed");
+ category.removePreference(shakePreference);
+ }
+ } else {
+ int i = shakePreference.findIndexOfValue(shakePreference.getValue());
+ shakePreference.setSummary(getString(
+ R.string.shake_action_summary,
+ getResources().getStringArray(
+ R.array.action_summary_entries)[i]));
+ shakePreference.setOnPreferenceChangeListener(this);
+ }
+ }
}
private void updateAutoSnoozeSummary(ListPreference listPref, String delay) {
@@ -387,4 +448,25 @@ public final class SettingsActivity extends BaseActivity {
}
}
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ switch (requestCode) {
+ case AlarmClockFragment.REQUEST_CODE_RINGTONE:
+ mdefaultAlarmTone.saveRingtoneUri(data);
+ break;
+ case AlarmClockFragment.REQUEST_CODE_EXTERN_AUDIO:
+ if (!AlarmUtils.hasPermissionToDisplayRingtoneTitle(this, data.getData())) {
+ final String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE};
+ requestPermissions(perms, AlarmClockFragment.REQUEST_CODE_PERMISSIONS);
+ }
+ mdefaultAlarmTone.saveRingtoneUri(data);
+ break;
+ default:
+ LogUtils.w("Unhandled request code in onActivityResult: "
+ + requestCode);
+ }
+ }
+ }
}
diff --git a/src/com/android/deskclock/worldclock/AddCityDialog.java b/src/com/android/deskclock/worldclock/AddCityDialog.java
index c7174aa89..9612eb4a5 100644..100755
--- a/src/com/android/deskclock/worldclock/AddCityDialog.java
+++ b/src/com/android/deskclock/worldclock/AddCityDialog.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +18,7 @@
package com.android.deskclock.worldclock;
+import android.Manifest;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -25,6 +28,7 @@ import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.AnimationDrawable;
@@ -51,10 +55,11 @@ import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
-import android.widget.Spinner;
import android.widget.Toast;
+import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
+import com.android.deskclock.Utils;
import com.android.deskclock.worldclock.CityAndTimeZoneLocator.OnCityAndTimeZoneLocatedCallback;
import com.android.deskclock.worldclock.CityAndTimeZoneLocator.TZ;
@@ -64,6 +69,7 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
import java.util.TimeZone;
public class AddCityDialog implements OnClickListener,
@@ -71,9 +77,14 @@ public class AddCityDialog implements OnClickListener,
private static final int HOURS_1 = 60 * 60000;
private static final long GPS_TIMEOUT = 30000L;
-
private static final String STATE_CITY_NAME = "city_name";
private static final String STATE_CITY_TIMEZONE = "city_tz";
+ private static final String ISGPSREQUESTING = "city_dialog";
+ private int mCityDialogWidth = -1;
+ private int mCityDialogHeight = -1;
+ public static CityTimeZone[] mZones;
+
+ static final int REQUEST_FINE_LOCATION_PERMISSIONS = 20;
public interface OnCitySelected {
public void onCitySelected(String city, String tz);
@@ -81,27 +92,22 @@ public class AddCityDialog implements OnClickListener,
}
private final AsyncTask<Void, Void, Void> mTzLoadTask = new AsyncTask<Void, Void, Void>() {
- private String[] mZones;
+
@Override
protected Void doInBackground(Void... params) {
List<CityTimeZone> zones = loadTimeZones();
Collections.sort(zones);
- List<String> tzLabels = new ArrayList<String>();
- for (CityTimeZone zone : zones) {
- tzLabels.add(zone.toString());
- }
-
- mZones = tzLabels.toArray(new String[tzLabels.size()]);
- mDefaultTimeZoneId = zones.indexOf(mDefaultTimeZoneLabel);
+ mZones = zones.toArray(new CityTimeZone[zones.size()]);
+ mDefaultTimeZonePos = zones.indexOf(mDefaultTimeZone);
return null;
}
@Override
protected void onPostExecute(Void result) {
if (!isCancelled()) {
- int id = mSavedTimeZonePos != -1 ? mSavedTimeZonePos : mDefaultTimeZoneId;
+ int id = mSavedTimeZonePos != -1 ? mSavedTimeZonePos : mDefaultTimeZonePos;
setTimeZoneData(mZones, id, true);
mLoadingTz = false;
}
@@ -128,11 +134,17 @@ public class AddCityDialog implements OnClickListener,
stopGpsAnimation();
mGps.setImageResource(R.drawable.ic_gps);
checkSelectionStatus();
- mLocationMgr.removeUpdates(AddCityDialog.this);
+ try {
+ mLocationMgr.removeUpdates(AddCityDialog.this);
+ } catch (SecurityException e){
+ LogUtils.d(LogUtils.LOGTAG, "Runnable mGpsTimeout:occur security exception");
+ }
+
}
};
- private static class CityTimeZone implements Comparable<CityTimeZone> {
+ public static class CityTimeZone implements Comparable<CityTimeZone> {
+ String mId;
int mSign;
int mHours;
int mMinutes;
@@ -141,6 +153,10 @@ public class AddCityDialog implements OnClickListener,
@Override
public String toString() {
+ if (mId == null) {
+ // Loading
+ return mLabel;
+ }
return String.format("GMT%s%02d:%02d - %s",
(mSign == -1 ? "-" : "+"), mHours, mMinutes, mLabel);
}
@@ -155,8 +171,8 @@ public class AddCityDialog implements OnClickListener,
@Override
public int compareTo(CityTimeZone other) {
- int offset = getOffset();
- int otherOffset = other.getOffset();
+ long offset = getOffset();
+ long otherOffset = other.getOffset();
if (offset != otherOffset) {
return offset < otherOffset ? -1 : 1;
}
@@ -166,8 +182,8 @@ public class AddCityDialog implements OnClickListener,
return mLabel.compareTo(other.mLabel);
}
- private int getOffset() {
- return mSign * (mHours + mMinutes * 60);
+ private long getOffset() {
+ return mSign * (mHours * HOURS_1 + mMinutes * 60000);
}
}
@@ -175,50 +191,47 @@ public class AddCityDialog implements OnClickListener,
private final Handler mHandler;
private final OnCitySelected mListener;
private final AlertDialog mDialog;
- private final EditText mCityName;
+ private final View dlgView;
+ private EditText mCityName;
private final ImageButton mGps;
- private final Spinner mTimeZones;
private Button mButton;
-
- private List<String> mCurrentTimeZones;
+ public static TimeZoneSpinner mTimeZones;
private LocationManager mLocationMgr;
private ConnectivityManager mConnectivityMgr;
private CityAndTimeZoneLocator mLocator;
- private boolean mGpsRequesting;
private boolean mLoadingTz;
+ public boolean mGpsRequesting;
- private int mDefaultTimeZoneId;
+ private int mDefaultTimeZonePos;
private int mSavedTimeZonePos;
- private CityTimeZone mDefaultTimeZoneLabel;
+ private CityTimeZone mDefaultTimeZone;
public AddCityDialog(Context context, LayoutInflater inflater, OnCitySelected listener) {
mContext = context;
mHandler = new Handler();
mListener = listener;
- mDefaultTimeZoneId = 0;
- mDefaultTimeZoneLabel = null;
+ mDefaultTimeZonePos = 0;
+ mDefaultTimeZone = null;
mSavedTimeZonePos = -1;
+
mLocationMgr = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- mLocationMgr.addGpsStatusListener(new GpsStatus.Listener() {
- @Override
- public void onGpsStatusChanged(int event) {
- }
- });
- mConnectivityMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mConnectivityMgr = (ConnectivityManager)context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
mGpsRequesting = false;
mLoadingTz = true;
// Initialize dialog
- View dlgView = inflater.inflate(R.layout.city_add, null);
+ dlgView = inflater.inflate(R.layout.city_add, null);
mCityName = (EditText) dlgView.findViewById(R.id.add_city_name);
mCityName.addTextChangedListener(this);
-
- mTimeZones = (Spinner) dlgView.findViewById(R.id.add_city_tz);
- setTimeZoneData(new String[]{ context.getString(R.string.cities_add_loading) }, 0, false);
+ mTimeZones = (TimeZoneSpinner) dlgView.findViewById(R.id.add_city_tz);
+ CityTimeZone loading = new CityTimeZone();
+ loading.mId = null;
+ loading.mLabel = context.getString(R.string.cities_add_loading);
+ setTimeZoneData(new CityTimeZone[]{ loading }, 0, false);
mTimeZones.setEnabled(false);
mTimeZones.setOnItemSelectedListener(this);
-
mGps = (ImageButton)dlgView.findViewById(R.id.add_city_gps);
mGps.setOnClickListener(new View.OnClickListener() {
@Override
@@ -242,7 +255,17 @@ public class AddCityDialog implements OnClickListener,
return true;
}
});
+
checkGpsAvailability();
+ try {
+ mLocationMgr.addGpsStatusListener(new GpsStatus.Listener() {
+ @Override
+ public void onGpsStatusChanged(int event) {
+ }
+ });
+ } catch (SecurityException e) {
+ LogUtils.d(LogUtils.LOGTAG, "AddCityDialog:occur security exception");
+ }
// Create the dialog
AlertDialog.Builder builder = new AlertDialog.Builder(context);
@@ -284,11 +307,14 @@ public class AddCityDialog implements OnClickListener,
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mReceiver, filter);
mReceiverRegistered = true;
+ mCityDialogWidth = dlgView.getWidth();
+ mCityDialogHeight = dlgView.getHeight();
}
- private void setTimeZoneData(String[] data, int selected, boolean enabled) {
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,
- android.R.layout.simple_spinner_item, data);
+ public void setTimeZoneData(CityTimeZone[] data, int selected,
+ boolean enabled) {
+ ArrayAdapter<CityTimeZone> adapter = new ArrayAdapter<CityTimeZone>(
+ mContext, android.R.layout.simple_spinner_item, data);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mTimeZones.setAdapter(adapter);
mTimeZones.setSelection(selected);
@@ -296,15 +322,13 @@ public class AddCityDialog implements OnClickListener,
if (mButton != null) {
checkSelectionStatus();
}
-
- mCurrentTimeZones = Arrays.asList(data);
}
private List<CityTimeZone> loadTimeZones() {
ArrayList<CityTimeZone> timeZones = new ArrayList<CityTimeZone>();
Resources res = mContext.getResources();
final long date = Calendar.getInstance().getTimeInMillis();
- mDefaultTimeZoneLabel = buildCityTimeZone(TimeZone.getDefault().getID(), date);
+ mDefaultTimeZone = buildCityTimeZone(TimeZone.getDefault().getID(), date);
String[] ids = res.getStringArray(R.array.cities_tz);
for (String id : ids) {
CityTimeZone zone = buildCityTimeZone(id, date);
@@ -325,6 +349,7 @@ public class AddCityDialog implements OnClickListener,
final boolean inDst = tz.inDaylightTime(new Date(date));
CityTimeZone timeZone = new CityTimeZone();
+ timeZone.mId = tz.getID();
timeZone.mLabel = tz.getDisplayName(inDst, TimeZone.LONG);
timeZone.mSign = offset < 0 ? -1 : 1;
timeZone.mHours = p / (HOURS_1);
@@ -346,10 +371,13 @@ public class AddCityDialog implements OnClickListener,
} else {
id = info.name;
}
-
return buildCityTimeZone(id, date);
}
+ public static void setSelectItem(int itemId) {
+ mTimeZones.setSelection(itemId);
+ }
+
private void checkSelectionStatus() {
String name = mCityName.getText().toString().toLowerCase();
String tz = null;
@@ -361,12 +389,32 @@ public class AddCityDialog implements OnClickListener,
mCityName.isEnabled() && !TextUtils.isEmpty(name) &&
mTimeZones.isEnabled() && !TextUtils.isEmpty(tz);
mButton.setEnabled(enabled);
+ if (enabled) {
+ mButton.setTextColor(mContext.getResources().getColor(
+ R.color.color_accent, null));
+ } else {
+ mButton.setTextColor(mContext.getResources().getColor(
+ R.color.dialog_positive_button_disable, null));
+ }
}
private void checkGpsAvailability() {
boolean gpsEnabled = mLocationMgr.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean networkEnabled = mLocationMgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
mGps.setEnabled(gpsEnabled || (networkEnabled && isNetworkStatusAvailable()));
+ LogUtils.d(LogUtils.LOGTAG, "checkGpsAvailability: gpsEnabled = "
+ + gpsEnabled + " networkEnabled = " + networkEnabled);
+
+ //check & request gps permission when GPS enable, if gps disable, don't
+ if(gpsEnabled || (networkEnabled && isNetworkStatusAvailable())) {
+ if(!hasPermissionOfFineLocation(mContext)
+ && Utils.isMOrLater()) {
+ LogUtils.d(LogUtils.LOGTAG, "checkGpsAvailability:request fine location permission");
+ final String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION};
+ ((CitySelectionActivity) mContext).requestPermissions(perms,
+ REQUEST_FINE_LOCATION_PERMISSIONS);
+ }
+ }
}
private boolean isNetworkStatusAvailable() {
@@ -381,7 +429,6 @@ public class AddCityDialog implements OnClickListener,
Criteria criteria = new Criteria();
criteria.setHorizontalAccuracy(Criteria.ACCURACY_LOW);
Looper looper = mContext.getMainLooper();
-
mHandler.postDelayed(mGpsTimeout, GPS_TIMEOUT);
mGpsRequesting = true;
mCityName.setEnabled(false);
@@ -397,18 +444,26 @@ public class AddCityDialog implements OnClickListener,
// We have to use the network to locate the city and tz, so user also the network to detect
// location (we not need to much accuracy and this method is faster). Otherwise, use
// the GPS to locate the coordinates
- if (mLocationMgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
- mLocationMgr.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER, 5000, 0, this, looper);
- } else {
- mLocationMgr.requestLocationUpdates(
- LocationManager.GPS_PROVIDER, 5000, 0, this, looper);
+ try {
+ if (mLocationMgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ mLocationMgr.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER, 5000, 0, this, looper);
+ } else {
+ mLocationMgr.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER, 5000, 0, this, looper);
+ }
+ } catch (SecurityException e) {
+ LogUtils.d(LogUtils.LOGTAG, "requestGpsLocation:occur security exception");
}
}
private void cancelRequestGpsLocation() {
mHandler.removeCallbacks(mGpsTimeout);
- mLocationMgr.removeUpdates(this);
+ try {
+ mLocationMgr.removeUpdates(this);
+ } catch (SecurityException e){
+ LogUtils.d(LogUtils.LOGTAG, "cancelRequestGpsLocation:occur security exception");
+ }
mGpsRequesting = false;
mCityName.setText("");
mCityName.setEnabled(true);
@@ -425,13 +480,13 @@ public class AddCityDialog implements OnClickListener,
}
public void onClick(DialogInterface dialog, int which) {
- String name = mCityName.getText().toString();
- String tz = null;
+ String name = mCityName.getText().toString().toUpperCase(Locale.getDefault());
+ CityTimeZone ctz = null;
if (mTimeZones.getSelectedItem() != null) {
- tz = mTimeZones.getSelectedItem().toString();
+ ctz = (CityTimeZone)mTimeZones.getSelectedItem();
}
- if (tz != null && mListener != null) {
- mListener.onCitySelected(name, tz.substring(tz.indexOf(" - ") + 3));
+ if (ctz != null && mListener != null) {
+ mListener.onCitySelected(name, ctz.mId);
}
}
@@ -458,19 +513,24 @@ public class AddCityDialog implements OnClickListener,
if (mTimeZones.getSelectedItem() != null) {
tz = mTimeZones.getSelectedItemPosition();
}
-
+ outState.putBoolean(ISGPSREQUESTING, mGpsRequesting);
outState.putString(STATE_CITY_NAME, name);
outState.putInt(STATE_CITY_TIMEZONE, tz);
}
protected void onRestoreInstanceState(Bundle savedInstanceState) {
String name = savedInstanceState.getString(STATE_CITY_NAME);
+ Boolean isGpsRequesting = savedInstanceState.getBoolean(ISGPSREQUESTING);
if (name != null) {
mCityName.setText(name);
}
+ if(isGpsRequesting){
+ mCityName.setText("");
+ }
mSavedTimeZonePos = savedInstanceState.getInt(STATE_CITY_TIMEZONE, -1);
}
+
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
checkSelectionStatus();
}
@@ -496,31 +556,26 @@ public class AddCityDialog implements OnClickListener,
if (!mGpsRequesting) return;
mGpsRequesting = false;
mHandler.removeCallbacks(mGpsTimeout);
- mLocationMgr.removeUpdates(this);
-
+ try {
+ mLocationMgr.removeUpdates(this);
+ } catch (SecurityException e) {
+ LogUtils.d(LogUtils.LOGTAG, "onLocationChanged:occur security exception");
+ }
CityAndTimeZoneLocator mLocator = new CityAndTimeZoneLocator(
mContext, location, mConnectivityMgr, new OnCityAndTimeZoneLocatedCallback() {
@Override
+ @SuppressWarnings("unchecked")
public void onCityAndTimeZoneLocated(String city, TZ timezone) {
- // Now we need to resolve the timezone info into an existing timezone
- // First try to resolve the id, otherwise select the first occurrence
- // with the same offset
- CityTimeZone ctzInfo = toCityTimeZone(timezone);
- int tz = mCurrentTimeZones.indexOf(ctzInfo.toString());
- if (tz == -1) {
- String offset = ctzInfo.toString().substring(0, 9); //xe: GMT+12:00
- int cc = mCurrentTimeZones.size();
- for (int i = 0; i < cc; i++) {
- String ctz = mCurrentTimeZones.get(i);
- if (ctz.startsWith(offset)) {
- tz = i;
- break;
- }
- }
+ CityTimeZone ctz = toCityTimeZone(timezone);
+ int pos = ((ArrayAdapter<CityTimeZone>)mTimeZones.getAdapter()).getPosition(ctz);
+ if (pos == -1) {
+ // This mean you are in the middle of the ocean and Android doesn't have
+ // a timezone definition for you.
+ pos = mDefaultTimeZonePos;
}
// Update the views with the new information
- updateViews(city, tz);
+ updateViews(city, pos);
}
@Override
@@ -567,4 +622,18 @@ public class AddCityDialog implements OnClickListener,
public void onProviderDisabled(String provider) {
checkGpsAvailability();
}
+
+
+ public static boolean hasPermissionOfFineLocation(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ final String packageName = context.getPackageName();
+
+ // If the permission is already granted, return true.
+ if (pm.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, packageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/com/android/deskclock/worldclock/CityAndTimeZoneLocator.java b/src/com/android/deskclock/worldclock/CityAndTimeZoneLocator.java
index afb1cb7ee..e5c46ab16 100644..100755
--- a/src/com/android/deskclock/worldclock/CityAndTimeZoneLocator.java
+++ b/src/com/android/deskclock/worldclock/CityAndTimeZoneLocator.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,19 +29,16 @@ import android.os.AsyncTask;
import android.util.Log;
import android.util.Xml;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
+import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
import java.util.List;
import java.util.Locale;
@@ -172,20 +171,20 @@ public class CityAndTimeZoneLocator {
private TZ resolveTimeZone() {
BufferedReader br = null;
try {
- HttpClient client = new DefaultHttpClient();
- boolean gps = mLocation.getProvider().compareTo(LocationManager.GPS_PROVIDER) == 0;
+ boolean gps = mLocation.getProvider().compareTo(
+ LocationManager.GPS_PROVIDER) == 0;
final URI uri = new URI(String.format(TIMEZONE_SERVICE_URI,
String.valueOf(mLocation.getLatitude()),
String.valueOf(mLocation.getLongitude()),
String.valueOf(System.currentTimeMillis() / 1000L),
String.valueOf(gps)));
- HttpGet request = new HttpGet();
- request.setURI(uri);
- HttpResponse response = client.execute(request);
- int status = response.getStatusLine().getStatusCode();
- if (status == HttpStatus.SC_OK) {
- // Read the response into XML
- br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+ URL url = new URL(uri.toString());
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ int status = conn.getResponseCode();
+ if (status == HttpURLConnection.HTTP_OK) {
+ br = new BufferedReader(new InputStreamReader(
+ conn.getInputStream()));
return parseTimeZoneResponse(br);
}
} catch (URISyntaxException e) {
diff --git a/src/com/android/deskclock/worldclock/CitySelectionActivity.java b/src/com/android/deskclock/worldclock/CitySelectionActivity.java
index 2c8e39874..d6f62fa28 100644
--- a/src/com/android/deskclock/worldclock/CitySelectionActivity.java
+++ b/src/com/android/deskclock/worldclock/CitySelectionActivity.java
@@ -41,6 +41,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.deskclock.BaseActivity;
+import com.android.deskclock.LogUtils;
import com.android.deskclock.R;
import com.android.deskclock.Utils;
import com.android.deskclock.actionbarmenu.AbstractMenuItemController;
@@ -92,15 +93,16 @@ public final class CitySelectionActivity extends BaseActivity
/** Menu item controller for search view. */
private SearchMenuItemController mSearchMenuItemController;
- private static final String STATE_CITY_DIALOG = "city_dialog";
-
- private AddCityDialog mAddCityDialog;
+ private LayoutInflater mFactory;
+ private AddCityDialog mAddCityDialog = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(AudioManager.STREAM_ALARM);
+ mFactory = LayoutInflater.from(this);
+
setContentView(R.layout.cities_activity);
mSearchMenuItemController =
new SearchMenuItemController(new SearchView.OnQueryTextListener() {
@@ -119,6 +121,7 @@ public final class CitySelectionActivity extends BaseActivity
mCitiesAdapter = new CityAdapter(this, mSearchMenuItemController);
mActionBarMenuManager.addMenuItemController(new NavUpMenuItemController(this))
.addMenuItemController(mSearchMenuItemController)
+ .addMenuItemController(new AddCityMenuItemController())
.addMenuItemController(new SortOrderMenuItemController())
.addMenuItemController(new SettingMenuItemController(this))
.addMenuItemController(MenuItemControllerFactory.getInstance()
@@ -209,7 +212,7 @@ public final class CitySelectionActivity extends BaseActivity
* </pre>
*/
private static final class CityAdapter extends BaseAdapter implements View.OnClickListener,
- CompoundButton.OnCheckedChangeListener, SectionIndexer {
+ CompoundButton.OnCheckedChangeListener, SectionIndexer, View.OnLongClickListener {
/** The type of the single optional "Selected Cities" header entry. */
private static final int VIEW_TYPE_SELECTED_CITIES_HEADER = 0;
@@ -251,9 +254,8 @@ public final class CitySelectionActivity extends BaseActivity
/** Menu item controller for search. Search query is maintained here. */
private final SearchMenuItemController mSearchMenuItemController;
- private final int mClockWhiteColor;
- private final int mClockBlueColor;
-
+ private final int mNormalCityFgColor;
+ private final int mUserDefinedCityFgColor;
public CityAdapter(Context context, SearchMenuItemController searchMenuItemController) {
mContext = context;
@@ -276,8 +278,8 @@ public final class CitySelectionActivity extends BaseActivity
mPattern12 = pattern12;
Resources res = context.getResources();
- mClockWhiteColor = res.getColor(R.color.clock_white);
- mClockBlueColor = res.getColor(R.color.clock_blue);
+ mNormalCityFgColor = res.getColor(R.color.clock_white);
+ mUserDefinedCityFgColor = res.getColor(R.color.red);
}
@Override
@@ -307,30 +309,6 @@ public final class CitySelectionActivity extends BaseActivity
return position;
}
- public int getPosition(CityObj o) {
- int count = mAllTheCitiesList.length;
- for (int i = 0; i < count; i++) {
- CityObj c = (CityObj) mAllTheCitiesList[i];
- if (c.mCityId != null && o.mCityId.compareTo(c.mCityId) == 0) {
- return i;
- }
- }
- return -1;
- }
-
- public int getPosition(String name, String tz) {
- int count = mAllTheCitiesList.length;
- for (int i = 0; i < count; i++) {
- CityObj c = (CityObj) mAllTheCitiesList[i];
- if (c.mCityId != null &&
- name.compareToIgnoreCase(c.mCityName) == 0 &&
- tz.compareToIgnoreCase(c.mTimeZone) == 0) {
- return i;
- }
- }
- return -1;
- }
-
@Override
public synchronized View getView(int position, View view, ViewGroup parent) {
final int itemViewType = getItemViewType(position);
@@ -364,6 +342,11 @@ public final class CitySelectionActivity extends BaseActivity
holder.name.setText(city.getName(), TextView.BufferType.SPANNABLE);
holder.time.setText(getTimeCharSequence(timeZone));
+ view.setOnLongClickListener(this);
+ boolean bIsUserAdded = city.getId().length()> 2
+ && "UD".equalsIgnoreCase(city.getId().substring(0,2));
+ holder.name.setTextColor(bIsUserAdded ? mUserDefinedCityFgColor : mNormalCityFgColor);
+
final boolean showIndex = getShowIndex(position);
holder.index.setVisibility(showIndex ? View.VISIBLE : View.INVISIBLE);
if (showIndex) {
@@ -419,6 +402,46 @@ public final class CitySelectionActivity extends BaseActivity
b.setChecked(!b.isChecked());
}
+ public boolean onLongClick(View v) {
+ final CityItemHolder holder = (CityItemHolder) v.getTag();
+ City c = (City)holder.selected.getTag();
+ if (c != null && "UD".equalsIgnoreCase(c.getId().substring(0,2))) {
+ deleteCity(c);
+ return true;
+ }
+ return false;
+ }
+
+ private void deleteCity(final City c) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(R.string.cities_delete_city_title);
+ builder.setMessage(mContext.getString(R.string.cities_delete_city_msg, c.getName()));
+ builder.setPositiveButton(mContext.getString(android.R.string.ok),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int id = Integer.parseInt(c.getId().substring(2));
+ if (DbCities.deleteCity(mContext, id) > 0) {
+ // Remove from the list and from the selection
+ mUserSelectedCities.remove(c.getId());
+
+ // set the selected cities in order to recreate list content
+ DataModel.getDataModel().setSelectedCities(getSelectedCities());
+
+ //refresh the list with the new data
+ refresh();
+ } else {
+ // Something went wrong
+ Toast.makeText(mContext, R.string.cities_delete_city_failed,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ builder.setNegativeButton(mContext.getString(android.R.string.cancel), null);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
@Override
public Object[] getSections() {
if (mSectionHeaders == null) {
@@ -640,111 +663,120 @@ public final class CitySelectionActivity extends BaseActivity
}
}
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
+ private class AddCityMenuItemController extends AbstractMenuItemController {
+ public int getId() {
+ return R.id.menu_item_add;
+ }
- if (mAddCityDialog != null) {
- outState.putBoolean(STATE_CITY_DIALOG, true);
- mAddCityDialog.onSaveInstanceState(outState);
+ public void showMenuItem(Menu menu) {
+ final MenuItem addMenuItem = menu.findItem(R.id.menu_item_add);
+ addMenuItem.setVisible(true);
}
- }
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
+ public boolean handleMenuItemClick(MenuItem item) {
+ LogUtils.d(LogUtils.LOGTAG, "AddCityMenuItemController: add city menu is clicked");
+ mAddCityDialog = new AddCityDialog(CitySelectionActivity.this,
+ mFactory, CitySelectionActivity.this);
+ try {
+ mAddCityDialog.show();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- if (savedInstanceState.getBoolean(STATE_CITY_DIALOG, false)) {
- showAddCityDialog(savedInstanceState);
+ return true;
}
}
@Override
- protected void onDestroy() {
- super.onDestroy();
-
- if (mAddCityDialog != null) {
- mAddCityDialog.dismiss();
- }
- }
+ public void onCitySelected(String name, String tz) {
+ LogUtils.d(LogUtils.LOGTAG, "onCitySelected: name = " + name + " tz = " + tz);
- private void showAddCityDialog(Bundle savedInstance) {
- mAddCityDialog = new AddCityDialog(this, mFactory, this);
- if (savedInstance != null) {
- mAddCityDialog.onRestoreInstanceState(savedInstance);
+ //validity check
+ if(name == null || name.isEmpty()
+ || tz == null || tz.isEmpty()) {
+ LogUtils.d(LogUtils.LOGTAG, "onCitySelected:value is invalid");
+ return;
}
- mAddCityDialog.show();
- }
- @Override
- public boolean onLongClick(View v) {
- CompoundButton b = (CompoundButton) v.findViewById(R.id.city_onoff);
- final CityObj c = (CityObj) b.getTag();
- if (c != null && c.mUserDefined) {
- deleteCity(c);
- return true;
+ //dismiss the dialog
+ if(mAddCityDialog != null) {
+ mAddCityDialog.dismiss();
+ mAddCityDialog = null;
}
- return false;
- }
- @Override
- public void onCitySelected(String name, String tz) {
- // If city name and timezone exists, then don't add it
- int pos = mAdapter.getPosition(name, tz);
- if (pos != -1) {
- // The city already exists
+ // If city name and timezone already exists in DB, give toast prompt
+ if (cityRecordIsExistInDB(name, tz)) {
+ //prompt the toast
Toast.makeText(this, R.string.cities_add_already_exists,
Toast.LENGTH_SHORT).show();
- mCitiesList.setSelection(pos);
return;
}
- DbCity dbCity = new DbCity();
- dbCity.name = name;
- dbCity.tz = tz;
- long id = DbCities.addCity(this, dbCity);
- if (id < 0) {
- // Something went wrong
- Toast.makeText(this, R.string.cities_add_city_failed,
- Toast.LENGTH_SHORT).show();
+ //insert new record to DB
+ if (insertNewRecordToClockDB(name, tz)) {
+ //recreate allCities selectedCities list
+ DataModel.getDataModel().setSelectedCities(mCitiesAdapter.getSelectedCities());
+
+ //refresh the list with the new data
+ mCitiesAdapter.refresh();
+ mCitiesList.invalidate();
} else {
- mAdapter.loadCitiesDataBase(this);
- mAdapter.notifyDataSetChanged();
- CityObj o = new CityObj(name, tz, "UD" + id);
- mCitiesList.setSelection(mAdapter.getPosition(o));
+ // Something went wrong
+ Toast.makeText(this, R.string.cities_add_city_failed,
+ Toast.LENGTH_SHORT).show();
}
-
- mAddCityDialog = null;
}
@Override
public void onCancelCitySelection() {
- mAddCityDialog = null;
+ //Dismiss Dialog
+ if(mAddCityDialog != null) {
+ mAddCityDialog.dismiss();
+ mAddCityDialog = null;
+ }
}
- private void deleteCity(final CityObj c) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.cities_delete_city_title);
- builder.setMessage(getString(R.string.cities_delete_city_msg, c.mCityName));
- builder.setPositiveButton(getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- int id = Integer.parseInt(c.mCityId.substring(2));
- if (DbCities.deleteCity(CitiesActivity.this, id) > 0) {
- // Remove from the list and from the selection
- mUserSelectedCities.remove(c.mCityId);
- mAdapter.loadCitiesDataBase(CitiesActivity.this);
- mAdapter.notifyDataSetChanged();
- } else {
- // Something went wrong
- Toast.makeText(CitiesActivity.this, R.string.cities_delete_city_failed,
- Toast.LENGTH_SHORT).show();
+ private boolean cityRecordIsExistInDB(String name, String timezone) {
+ //param check
+ if (name == null || name.isEmpty()
+ || timezone == null || timezone.isEmpty()) {
+ LogUtils.d(LogUtils.LOGTAG, "cityRecordIsExistInDB: param is invalid" +
+ " name = " + name + " timezone = " + timezone);
+ return false;
+ }
+
+ List<City> allCityList = DataModel.getDataModel().getAllCities();
+ for (int i = 0; i < allCityList.size(); i++) {
+ City c = allCityList.get(i);
+ if(c != null && c.getId() != null) {
+ if (c.getName().equalsIgnoreCase(name)
+ && c.getTimeZone().getID().equalsIgnoreCase(timezone)) {
+ return true;
}
}
- });
- builder.setNegativeButton(getString(android.R.string.cancel), null);
- AlertDialog dialog = builder.create();
- dialog.show();
+ }
+
+ return false;
}
+ //insert new record to DB, return whether succeed or not
+ private boolean insertNewRecordToClockDB(String name, String tz) {
+ //param check
+ if (name == null || name.isEmpty()
+ || tz == null || tz.isEmpty()) {
+ LogUtils.d(LogUtils.LOGTAG, "insertNewRecordToClockDB: param is invalid" +
+ " name = " + name + " timezone = " + tz);
+ return false;
+ }
+
+ DbCity dbCity = new DbCity();
+ dbCity.name = name;
+ dbCity.tz = tz;
+ long id = DbCities.addCity(this, dbCity);
+ if (id < 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
}
diff --git a/src/com/android/deskclock/worldclock/TimeZoneSpinner.java b/src/com/android/deskclock/worldclock/TimeZoneSpinner.java
new file mode 100755
index 000000000..90c454725
--- /dev/null
+++ b/src/com/android/deskclock/worldclock/TimeZoneSpinner.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.deskclock.worldclock;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.preference.PreferenceManager;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.android.deskclock.R;
+import com.android.deskclock.Utils;
+import com.android.deskclock.worldclock.AddCityDialog.CityTimeZone;
+
+public class TimeZoneSpinner extends Spinner {
+ private Context mContext;
+ private CityTimeZone[] data;
+ public AlertDialog mdialog;
+ private ViewHolder holder;
+ private LinearLayout ll_item;
+ private LayoutParams linearParams;
+ private SharedPreferences sp;
+ public ListView listView;
+ private int scrolledY;
+ private int mposition;
+ private static final int ITEM_COUNT_LAND = 5;
+ private static final int ITEM_COUNT_PORT = 7;
+ private static final String SELECTPOSITION = "select_position";
+ ArrayAdapter<CityTimeZone> adapter;
+
+ public TimeZoneSpinner(Context context) {
+ super(context);
+ mContext = context;
+ sp = Utils.getCESharedPreferences(mContext);
+ }
+
+ public TimeZoneSpinner(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ if (sp == null) {
+ sp = Utils.getCESharedPreferences(mContext);
+ }
+ }
+
+ @Override
+ public boolean performClick() {
+ data = AddCityDialog.mZones;
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
+ final View view = inflater.inflate(R.layout.time_zone_list, null);
+ // init listview
+ initListView(view);
+ creatDialog(view);
+ return true;
+ }
+
+ private void initListView(View view) {
+ listView = (ListView) view.findViewById(R.id.tz_list);
+ // set ListView'height According to spinner'location
+ int[] location = new int[2];
+ this.getLocationOnScreen(location);
+ final int spinnerLocationY = location[1];
+ ViewGroup.LayoutParams params = listView.getLayoutParams();
+ params.height = spinnerLocationY;
+ listView.setLayoutParams(params);
+ adapter = new ArrayAdapter<CityTimeZone>(getContext(),
+ R.layout.time_zone_list_item, data) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(mContext).inflate(
+ R.layout.time_zone_list_item, null);
+ holder = new ViewHolder();
+
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+ ll_item = (LinearLayout) convertView.findViewById(R.id.tz_ll);
+ holder.tView = (TextView) convertView
+ .findViewById(android.R.id.text1);
+ holder.tView.setText(data[position].toString());
+
+ linearParams = (LayoutParams) ll_item.getLayoutParams();
+
+ if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ linearParams.height = spinnerLocationY / ITEM_COUNT_LAND;
+ } else {
+ linearParams.height = spinnerLocationY / ITEM_COUNT_PORT;
+ }
+
+ ll_item.setLayoutParams(linearParams);
+ return convertView;
+ }
+ };
+ listView.setAdapter(adapter);
+ listView.setDivider(null);
+ listView.setSelection(sp.getInt(SELECTPOSITION, 0));
+ listView.setOnItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view,
+ int position, long id) {
+ AddCityDialog.setSelectItem(position);
+ mdialog.dismiss();
+ }
+ });
+ listView.setOnScrollListener(new OnScrollListener() {
+
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
+ mposition = listView.getFirstVisiblePosition();
+ sp.edit().putInt(SELECTPOSITION, mposition).commit();
+
+ }
+ }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem,
+ int visibleItemCount, int totalItemCount) {
+
+ }
+ });
+ }
+
+ private class ViewHolder {
+ TextView tView;
+ }
+
+ private void creatDialog(View view) {
+ mdialog = new AlertDialog.Builder(mContext).create();
+ Window mWindow = mdialog.getWindow();
+ mWindow.setGravity(Gravity.TOP);
+ WindowManager wm = (WindowManager) mContext
+ .getSystemService(Context.WINDOW_SERVICE);
+ WindowManager.LayoutParams lp = mWindow.getAttributes();
+ mdialog.setCanceledOnTouchOutside(true);
+ mdialog.show();
+ mdialog.addContentView(view, lp);
+ }
+}
diff --git a/src/com/android/deskclock/worldclock/db/DbCities.java b/src/com/android/deskclock/worldclock/db/DbCities.java
index fb496f8cf..87b92955f 100644..100755
--- a/src/com/android/deskclock/worldclock/db/DbCities.java
+++ b/src/com/android/deskclock/worldclock/db/DbCities.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/com/android/deskclock/worldclock/db/DbCity.java b/src/com/android/deskclock/worldclock/db/DbCity.java
index 6fa4bbad5..8ebccf938 100644..100755
--- a/src/com/android/deskclock/worldclock/db/DbCity.java
+++ b/src/com/android/deskclock/worldclock/db/DbCity.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/com/android/deskclock/worldclock/db/DbCityDatabaseHelper.java b/src/com/android/deskclock/worldclock/db/DbCityDatabaseHelper.java
index ca2f4c6df..e813464f3 100644..100755
--- a/src/com/android/deskclock/worldclock/db/DbCityDatabaseHelper.java
+++ b/src/com/android/deskclock/worldclock/db/DbCityDatabaseHelper.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/com/android/deskclock/worldclock/db/DbCityProvider.java b/src/com/android/deskclock/worldclock/db/DbCityProvider.java
index 710344053..d2bb9a13b 100644..100755
--- a/src/com/android/deskclock/worldclock/db/DbCityProvider.java
+++ b/src/com/android/deskclock/worldclock/db/DbCityProvider.java
@@ -1,4 +1,6 @@
-/*
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -167,7 +169,8 @@ public class DbCityProvider extends ContentProvider {
int mpid = android.os.Process.myPid();
int cpid = android.os.Binder.getCallingPid();
if (mpid != cpid) {
- throw new SecurityException("Permission Denial: writing is only allowed to DeskClock app.");
+ throw new SecurityException("Permission Denial:"
+ + "writing is only allowed to DeskClock app.");
}
}
}