summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2014-11-12 17:14:27 -0800
committerAdnan Begovic <adnan@cyngn.com>2015-10-26 16:11:13 -0700
commitd40cd5728a415efd72ee192fa6f67727411ed959 (patch)
treeae0afabb0d80930130005dd09c6c864e9177cfb1
parentcf65d3f14dce8dae3590daac56bdd59be28e1779 (diff)
downloadpackages_apps_Settings-d40cd5728a415efd72ee192fa6f67727411ed959.zip
packages_apps_Settings-d40cd5728a415efd72ee192fa6f67727411ed959.tar.gz
packages_apps_Settings-d40cd5728a415efd72ee192fa6f67727411ed959.tar.bz2
Profiles : Settings
Change-Id: I072758a1c5ec04ef34077551220b6611068fe71d
-rw-r--r--AndroidManifest.xml56
-rw-r--r--res/drawable-hdpi/ic_location.pngbin0 -> 1183 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_add.pngbin0 -> 667 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_nfc_writer_dark.pngbin0 -> 1385 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_trash_holo_dark.pngbin0 -> 972 bytes
-rw-r--r--res/drawable-hdpi/ic_settings_profiles.pngbin0 -> 1101 bytes
-rw-r--r--res/drawable-hdpi/nfc_writer.pngbin0 -> 6902 bytes
-rw-r--r--res/drawable-mdpi/ic_location.pngbin0 -> 837 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_add.pngbin0 -> 596 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_trash_holo_dark.pngbin0 -> 727 bytes
-rw-r--r--res/drawable-mdpi/ic_settings_profiles.pngbin0 -> 721 bytes
-rw-r--r--res/drawable-xhdpi/ic_location.pngbin0 -> 1604 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_add.pngbin0 -> 761 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_nfc_writer_dark.pngbin0 -> 1684 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_trash_holo_dark.pngbin0 -> 1219 bytes
-rw-r--r--res/drawable-xhdpi/ic_settings_profiles.pngbin0 -> 1761 bytes
-rw-r--r--res/drawable-xhdpi/nfc_writer.pngbin0 -> 6877 bytes
-rw-r--r--res/layout/nfc_select.xml49
-rw-r--r--res/layout/nfc_writer.xml57
-rw-r--r--res/layout/preference_name.xml58
-rw-r--r--res/layout/preference_profiles.xml96
-rw-r--r--res/layout/preference_profiles_widget.xml23
-rw-r--r--res/layout/preference_streamvolume.xml86
-rw-r--r--res/layout/profile_name_dialog.xml38
-rw-r--r--res/layout/profile_tabs.xml45
-rw-r--r--res/values/cm_arrays.xml83
-rw-r--r--res/values/cm_strings.xml118
-rw-r--r--res/values/styles.xml5
-rw-r--r--res/xml/appgroup_list.xml22
-rw-r--r--res/xml/application_list.xml30
-rw-r--r--res/xml/dashboard_categories.xml8
-rw-r--r--res/xml/profile_config.xml42
-rw-r--r--res/xml/profile_settings.xml71
-rw-r--r--res/xml/profiles_settings.xml20
-rw-r--r--src/com/android/settings/Utils.java45
-rw-r--r--src/com/android/settings/profiles/AbstractTriggerPreference.java38
-rw-r--r--src/com/android/settings/profiles/AppGroupConfig.java438
-rw-r--r--src/com/android/settings/profiles/AppGroupList.java95
-rw-r--r--src/com/android/settings/profiles/ApplicationItemPreference.java67
-rw-r--r--src/com/android/settings/profiles/BluetoothTriggerPreference.java45
-rw-r--r--src/com/android/settings/profiles/NFCProfile.java155
-rw-r--r--src/com/android/settings/profiles/NFCProfileSelect.java121
-rw-r--r--src/com/android/settings/profiles/NFCProfileUtils.java129
-rw-r--r--src/com/android/settings/profiles/NFCProfileWriter.java115
-rw-r--r--src/com/android/settings/profiles/NamePreference.java126
-rw-r--r--src/com/android/settings/profiles/ProfileAirplaneModePreference.java171
-rw-r--r--src/com/android/settings/profiles/ProfileConfig.java479
-rw-r--r--src/com/android/settings/profiles/ProfileConnectionPreference.java167
-rw-r--r--src/com/android/settings/profiles/ProfileEnabler.java81
-rw-r--r--src/com/android/settings/profiles/ProfileGroupConfig.java149
-rw-r--r--src/com/android/settings/profiles/ProfileRingModePreference.java182
-rw-r--r--src/com/android/settings/profiles/ProfileRingtonePreference.java58
-rw-r--r--src/com/android/settings/profiles/ProfilesList.java103
-rw-r--r--src/com/android/settings/profiles/ProfilesPreference.java151
-rw-r--r--src/com/android/settings/profiles/ProfilesSettings.java337
-rw-r--r--src/com/android/settings/profiles/ProfilesUtils.java68
-rw-r--r--src/com/android/settings/profiles/StreamVolumePreference.java158
-rw-r--r--src/com/android/settings/profiles/TriggersFragment.java229
-rw-r--r--src/com/android/settings/profiles/WifiTriggerAPPreference.java57
59 files changed, 4671 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7923033..a7949a9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2160,6 +2160,62 @@
android:theme="@style/CryptKeeperBlankTheme"
/>
+ <!-- CyanogenMod activities Start -->
+ <activity android:name=".profiles.ProfilesSettings" />
+ <activity android:name="Settings$ProfilesSettingsActivity"
+ android:label="@string/profile_settings"
+ android:taskAffinity=""
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.settings.PROFILES_SETTINGS" />
+ <action android:name="com.android.settings.PROFILES_SETTINGS" />
+ <category android:name="android.intent.category.VOICE_LAUNCH" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.SHORTCUT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.profiles.ProfilesSettings" />
+ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+ android:resource="@id/profiles_settings" />
+ </activity>
+
+ <!-- Keep compatibility with old shortcuts. -->
+ <activity-alias android:name="ProfileSettings"
+ android:label="@string/profile_settings"
+ android:exported="true"
+ android:targetActivity="Settings$ProfilesSettingsActivity">
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.profiles.ProfilesSettings" />
+ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+ android:resource="@id/profiles_settings" />
+ </activity-alias>
+
+ <activity android:name=".profiles.ProfileConfig" />
+
+ <activity android:name=".profiles.AppGroupList" />
+
+ <activity android:name=".profiles.AppGroupConfig" />
+
+ <activity android:name=".profiles.ProfileGroupConfig" />
+
+ <activity android:name=".profiles.WifiTriggers" />
+
+ <activity android:name=".profiles.NFCProfileWriter" />
+
+ <activity android:name=".profiles.NFCProfileSelect" />
+
+ <activity android:name=".profiles.NFCProfile"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter>
+ <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="cm/profile" />
+ </intent-filter>
+ </activity>
+
+ <!-- CyanogenMod activities End -->
+
<!-- Pseudo-activity used to provide an intent-filter entry point to encryption settings -->
<activity android:name="Settings$CryptKeeperSettingsActivity"
android:label="@string/crypt_keeper_encrypt_title">
diff --git a/res/drawable-hdpi/ic_location.png b/res/drawable-hdpi/ic_location.png
new file mode 100644
index 0000000..be38c05
--- /dev/null
+++ b/res/drawable-hdpi/ic_location.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_add.png b/res/drawable-hdpi/ic_menu_add.png
new file mode 100644
index 0000000..4b68f52
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_add.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_nfc_writer_dark.png b/res/drawable-hdpi/ic_menu_nfc_writer_dark.png
new file mode 100644
index 0000000..88fe437
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_nfc_writer_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_trash_holo_dark.png b/res/drawable-hdpi/ic_menu_trash_holo_dark.png
new file mode 100644
index 0000000..c7a0832
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_trash_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_settings_profiles.png b/res/drawable-hdpi/ic_settings_profiles.png
new file mode 100644
index 0000000..f47568d
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_profiles.png
Binary files differ
diff --git a/res/drawable-hdpi/nfc_writer.png b/res/drawable-hdpi/nfc_writer.png
new file mode 100644
index 0000000..873e721
--- /dev/null
+++ b/res/drawable-hdpi/nfc_writer.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_location.png b/res/drawable-mdpi/ic_location.png
new file mode 100644
index 0000000..9bcee70
--- /dev/null
+++ b/res/drawable-mdpi/ic_location.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_add.png b/res/drawable-mdpi/ic_menu_add.png
new file mode 100644
index 0000000..15ffadd
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_add.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_trash_holo_dark.png b/res/drawable-mdpi/ic_menu_trash_holo_dark.png
new file mode 100644
index 0000000..b9575aa
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_trash_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_settings_profiles.png b/res/drawable-mdpi/ic_settings_profiles.png
new file mode 100644
index 0000000..cc740bd
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_profiles.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_location.png b/res/drawable-xhdpi/ic_location.png
new file mode 100644
index 0000000..0e0be6c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_location.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_add.png b/res/drawable-xhdpi/ic_menu_add.png
new file mode 100644
index 0000000..420510e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_add.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_nfc_writer_dark.png b/res/drawable-xhdpi/ic_menu_nfc_writer_dark.png
new file mode 100644
index 0000000..417ec98
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_nfc_writer_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_trash_holo_dark.png b/res/drawable-xhdpi/ic_menu_trash_holo_dark.png
new file mode 100644
index 0000000..33add13
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_trash_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings_profiles.png b/res/drawable-xhdpi/ic_settings_profiles.png
new file mode 100644
index 0000000..d6c6911
--- /dev/null
+++ b/res/drawable-xhdpi/ic_settings_profiles.png
Binary files differ
diff --git a/res/drawable-xhdpi/nfc_writer.png b/res/drawable-xhdpi/nfc_writer.png
new file mode 100644
index 0000000..60f4d6e
--- /dev/null
+++ b/res/drawable-xhdpi/nfc_writer.png
Binary files differ
diff --git a/res/layout/nfc_select.xml b/res/layout/nfc_select.xml
new file mode 100644
index 0000000..e72a979
--- /dev/null
+++ b/res/layout/nfc_select.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_centerInParent="true">
+
+ <TextView
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="30dip"
+ android:layout_marginEnd="30dip"
+ android:layout_marginBottom="30dip"
+ android:layout_gravity="center"
+ android:text="@string/profile_add_nfc_text" />
+
+ <Button android:id="@+id/add_tag"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_gravity="center"
+ android:text="@string/profile_select" />
+
+ </LinearLayout>
+</RelativeLayout>
diff --git a/res/layout/nfc_writer.xml b/res/layout/nfc_writer.xml
new file mode 100644
index 0000000..959217c
--- /dev/null
+++ b/res/layout/nfc_writer.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_centerInParent="true">
+
+ <TextView
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="30dip"
+ android:layout_marginEnd="30dip"
+ android:layout_marginBottom="30dip"
+ android:layout_gravity="center"
+ android:text="@string/profile_nfc_text" />
+
+ <ImageView
+ android:id="@+id/nfc_writer_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/nfc_writer" />
+
+ <TextView android:id="@+id/touch_tag"
+ style="?android:attr/textAppearanceLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_gravity="center"
+ android:text="@string/profile_write_touch_tag" />
+
+ </LinearLayout>
+</RelativeLayout>
diff --git a/res/layout/preference_name.xml b/res/layout/preference_name.xml
new file mode 100644
index 0000000..5b3ff86
--- /dev/null
+++ b/res/layout/preference_name.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical">
+
+ <LinearLayout
+ android:id="@+id/name_pref"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:paddingStart="@*android:dimen/preference_item_padding_side"
+ android:paddingEnd="?android:attr/scrollbarSize"
+ android:background="?android:attr/selectableItemBackground">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@*android:dimen/preference_icon_minWidth"
+ android:layout_marginEnd="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/preference_profiles.xml b/res/layout/preference_profiles.xml
new file mode 100644
index 0000000..916c2ee
--- /dev/null
+++ b/res/layout/preference_profiles.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical">
+
+ <LinearLayout
+ android:id="@+id/profiles_pref"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical|end"
+ android:orientation="vertical" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:paddingBottom="3dip"
+ android:visibility="gone"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="13sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:focusable="false"
+ android:maxLines="4" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="2dip"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <ImageView
+ android:id="@+id/profiles_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingStart="15dip"
+ android:paddingEnd="?android:attr/scrollbarSize"
+ android:src="@drawable/ic_sysbar_quicksettings"
+ android:contentDescription="@string/input_method_settings_button"
+ android:layout_gravity="center"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground" />
+
+</LinearLayout>
diff --git a/res/layout/preference_profiles_widget.xml b/res/layout/preference_profiles_widget.xml
new file mode 100644
index 0000000..ab63a10
--- /dev/null
+++ b/res/layout/preference_profiles_widget.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RadioButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:focusable="false"
+ android:clickable="false" />
diff --git a/res/layout/preference_streamvolume.xml b/res/layout/preference_streamvolume.xml
new file mode 100644
index 0000000..a6675f5
--- /dev/null
+++ b/res/layout/preference_streamvolume.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical" >
+
+ <LinearLayout
+ android:id="@+id/text_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:paddingStart="@*android:dimen/preference_item_padding_side"
+ android:paddingEnd="@*android:dimen/preference_item_padding_inner"
+ android:background="?android:attr/selectableItemBackground">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
+ android:paddingStart="@*android:dimen/preference_icon_minWidth" >
+
+ <TextView android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@+android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="2" />
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="2dip"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@android:drawable/divider_horizontal_dark" />
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="68dip"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <CheckBox
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/profile_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:gravity="center" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/profile_name_dialog.xml b/res/layout/profile_name_dialog.xml
new file mode 100644
index 0000000..e7c2ed3
--- /dev/null
+++ b/res/layout/profile_name_dialog.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright (C) 2013 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:orientation="vertical"
+ android:padding="16dip">
+
+ <TextView
+ android:id="@+id/prompt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dip"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <EditText
+ android:id="@+id/name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
diff --git a/res/layout/profile_tabs.xml b/res/layout/profile_tabs.xml
new file mode 100644
index 0000000..7c8f6cb
--- /dev/null
+++ b/res/layout/profile_tabs.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+ <android.support.v4.view.PagerTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:textAppearance="@style/TextAppearance.PagerTabs"
+ android:paddingStart="@dimen/pager_tabs_padding"
+ android:paddingEnd="@dimen/pager_tabs_padding">
+ </android.support.v4.view.PagerTabStrip>
+ </android.support.v4.view.ViewPager>
+
+ <TextView
+ android:id="@+id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/profile_empty_list_profiles_off"
+ android:gravity="center" />
+
+</LinearLayout>
diff --git a/res/values/cm_arrays.xml b/res/values/cm_arrays.xml
index 2692f43..3582200 100644
--- a/res/values/cm_arrays.xml
+++ b/res/values/cm_arrays.xml
@@ -29,4 +29,87 @@
<item>2</item>
<item>3</item>
</string-array>
+
+ <!-- Ring mode options. -->
+ <string-array name="ring_mode_entries" translatable="false">
+ <item>@string/ring_mode_normal</item>
+ <item>@string/ring_mode_vibrate</item>
+ <item>@string/ring_mode_mute</item>
+ </string-array>
+
+ <!-- Values for Ring mode. Do not translate. -->
+ <string-array name="ring_mode_values" translatable="false">
+ <item>normal</item>
+ <item>vibrate</item>
+ <item>mute</item>
+ </string-array>
+
+ <!-- Profile mode options. -->
+ <string-array name="profile_entries">
+ <item>On</item>
+ <item>Off</item>
+ <item>No override</item>
+ </string-array>
+
+ <!-- Values for vibrate_entries matching constants in SoundSettings. Do not translate. -->
+ <string-array name="profile_values" translatable="false">
+ <item>OVERRIDE</item>
+ <item>SUPPRESS</item>
+ <item>DEFAULT</item>
+ </string-array>
+
+ <!-- Profile mode options. -->
+ <string-array name="profile_connection_entries">
+ <item>Disable</item>
+ <item>Enable</item>
+ </string-array>
+
+ <!-- Profile 2G-3G mode options. -->
+ <string-array name="profile_networkmode_entries" translatable="false">
+ <item>@string/profile_networkmode_2g</item>
+ <item>@string/profile_networkmode_3g</item>
+ <item>@string/profile_networkmode_2g3g</item>
+ </string-array>
+
+ <!-- Values for profile connections. Do not translate. -->
+ <string-array name="profile_connection_values" translatable="false">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ </string-array>
+
+ <!-- Values for profile Wi-Fi triggers -->
+ <string-array name="profile_trigger_wifi_options" translatable="false">
+ <item>@string/profile_trigger_connect</item>
+ <item>@string/profile_trigger_disconnect</item>
+ <item>@string/profile_trigger_notrigger</item>
+ </string-array>
+
+ <!-- Values for profile trigger types -->
+ <string-array name="profile_trigger_filters" translatable="false">
+ <item>@string/profile_trigger_filter_all</item>
+ <item>@string/profile_trigger_filter_wifi</item>
+ <item>@string/profile_trigger_filter_bluetooth</item>
+ </string-array>
+
+ <!-- Profile lock mode options. Do not translate. -->
+ <string-array name="profile_lockmode_entries" translatable="false">
+ <item>@string/profile_lockmode_default</item>
+ <item>@string/profile_lockmode_insecure</item>
+ <item>@string/profile_lockmode_disabled</item>
+ </string-array>
+
+ <!-- Profile lock mode summaries. Do not translate. -->
+ <string-array name="profile_lockmode_summaries" translatable="false">
+ <item>@string/profile_lockmode_default_summary</item>
+ <item>@string/profile_lockmode_insecure_summary</item>
+ <item>@string/profile_lockmode_disabled_summary</item>
+ </string-array>
+
+ <!-- Values for profile lock mode. Do not translate. -->
+ <string-array name="profile_lockmode_values" translatable="false">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ </string-array>
</resources>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 5d9bd49..6008082 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -45,4 +45,122 @@
<!-- Themes Settings -->
<!-- Settings main menu entry -->
<string name="themes_settings_title">Themes</string>
+
+ <!-- Sound settings screen -->
+ <string name="ring_mode_title">Ring mode</string>
+ <string name="ring_mode_normal">Normal</string>
+ <string name="ring_mode_vibrate">Vibrate</string>
+ <string name="ring_mode_mute">Mute</string>
+
+ <!-- Profiles settings -->
+ <string name="profiles_settings_title">Profiles</string>
+ <string name="profiles_add">Add</string>
+ <string name="profile_menu_delete">Delete</string>
+ <string name="profile_settings_title">Profile</string>
+ <string name="profile_empty_list_profiles_off">To configure and use system profiles, turn profiles on.</string>
+ <string name="profile_trigger_configure">Configure trigger</string>
+ <string name="profile_triggers">Triggers</string>
+ <string name="profile_trigger_filter_all">All triggers</string>
+ <string name="profile_trigger_filter_wifi">Wi-Fi triggers</string>
+ <string name="profile_trigger_filter_bluetooth">Bluetooth triggers</string>
+ <string name="profile_write_nfc_tag">Write to NFC tag</string>
+ <string name="profile_write_touch_tag">Touch tag to write</string>
+ <string name="profile_write_success">Tag successfully written</string>
+ <string name="profile_write_failed">Tag writing failed!</string>
+ <string name="profile_selected">Profile selected: %1$s</string>
+ <string name="profile_nfc_text">Writing a profile to a NFC tag allows for tapping the tag to select the profile. Tapping a second time will select the previously selected profile.</string>
+ <string name="profile_unknown_nfc_tag">Unknown profile</string>
+ <string name="profile_add_nfc_text">This NFC tag refers to an unknown profile. Attaching this NFC tag to an existing profile will allow for selecting the profile in the future.</string>
+ <string name="profile_select">Select profile</string>
+
+ <!-- Add Profile -->
+ <string name="add_profile_dialog_title">Create new profile</string>
+ <string name="profile_name_title">Name</string>
+ <string name="profile_profile_name_prompt">Enter a name for the new profile</string>
+ <string name="menu_new_profile">New profile</string>
+ <string name="new_profile_name">&lt;new profile&gt;</string>
+
+ <!-- Rename Dialog -->
+ <string name="rename_dialog_title">Rename</string>
+ <string name="rename_dialog_message">Enter a new name</string>
+ <string name="duplicate_profile_name">Duplicate profile name!</string>
+ <string name="duplicate_appgroup_name">Duplicate app group name!</string>
+
+ <!-- Reset Profiles -->
+ <string name="profile_reset_title">Reset</string>
+ <string name="profile_reset_message">Delete all user created profiles and app groups and restore them to default?</string>
+
+ <!-- Delete confimation messages -->
+ <string name="profile_delete_confirm">Delete this profile?</string>
+ <string name="profile_app_delete_confirm">Remove this app?</string>
+ <string name="profile_cannot_delete">An active profile cannot be deleted</string>
+
+ <!-- Profile network mode -->
+ <string name="profile_networkmode_2g">2G</string>
+ <string name="profile_networkmode_3g">3G</string>
+ <string name="profile_networkmode_2g3g">2G/3G</string>
+
+ <!-- Profile Config screen PreferenceGroup titles -->
+ <string name="profile_connectionoverrides_title">Connection overrides</string>
+ <string name="profile_volumeoverrides_title">Volume overrides</string>
+ <string name="connection_state_disabled">Disable</string>
+ <string name="connection_state_enabled">Enable</string>
+ <string name="volume_override_summary">Set to</string>
+
+ <!-- Menu item for managing profiles -->
+ <string name="profile_profiles_manage">Profiles</string>
+ <string name="profile_profile_manage">Manage profile</string>
+ <string name="profile_appgroups_manage">App groups</string>
+ <string name="profile_appgroup_manage">Manage app group</string>
+
+ <!-- Profile settings screen, section header for settings related to notification profiles -->
+ <string name="profile_settings">Profile settings</string>
+ <string name="profile_trigger_connect">On connect</string>
+ <string name="profile_trigger_disconnect">On disconnect</string>
+ <string name="profile_trigger_notrigger">No trigger</string>
+
+ <!-- Profile Settings sound modes labels -->
+ <string name="sound_mode">Notification mode</string>
+ <string name="ringer_mode">Ring mode</string>
+ <string name="lights_mode">Lights mode</string>
+ <string name="vibrate_mode">Vibrate mode</string>
+ <string name="choose_soundtone">Choose notification tone</string>
+ <string name="choose_ringtone">Choose ringtone</string>
+
+ <!-- Sound settings screen, setting option name to pick ringtone (a list dialog comes up)-->
+ <string name="soundtone_title">Notification tone</string>
+ <string name="soundtone_summary" translatable="false">""</string>
+
+ <!-- Title for application group setting screen -->
+ <string name="profile_appgroups_title">App groups</string>
+ <string name="profile_applist_title">Apps</string>
+ <string name="profile_new_appgroup">New app group</string>
+ <string name="profile_delete_appgroup">Delete this app group?</string>
+ <string name="profile_appgroup_name_prompt">Enter a name for the new app group</string>
+ <string name="profile_appgroup_name_title">Name</string>
+
+ <!-- Add application dialog box title -->
+ <string name="profile_choose_app">Choose app</string>
+
+ <!-- Profiles - system settings -->
+ <string name="profile_system_settings_title">System settings</string>
+ <string name="profile_lockmode_title">Lock screen mode</string>
+ <string name="profile_lockmode_default">Default</string>
+ <string name="profile_lockmode_insecure">Insecure</string>
+ <string name="profile_lockmode_disabled">Disabled</string>
+ <string name="profile_lockmode_default_summary">Use system default</string>
+ <string name="profile_lockmode_insecure_summary">Use insecure lock screen</string>
+ <string name="profile_lockmode_disabled_summary">Lock screen is disabled</string>
+ <string name="profile_airplanemode_title">Airplane mode</string>
+
+ <!-- Connection override toggles (not all are used at this time ) -->
+ <string name="toggleWifi">Wi-Fi</string>
+ <string name="toggleWifiAp">Portable Wi-Fi hotspot</string>
+ <string name="toggleBluetooth">Bluetooth</string>
+ <string name="toggleGPS">GPS</string>
+ <string name="toggleData">Mobile Data</string>
+ <string name="toggleSync">Data Sync</string>
+ <string name="toggle2g3g">2G/3G</string>
+ <string name="toggleWimax">WiMAX</string>
+ <string name="toggleNfc">NFC</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 387acf5..84501c3 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -357,4 +357,9 @@
<style name="SetupWizardStorageStyle" parent="@style/SuwThemeMaterial.Light">
<item name="android:colorAccent">#ff009688</item>
</style>
+
+ <style name="ProfilesPreferenceStyle">
+ <item name="android:layout">@layout/preference_profiles</item>
+ <item name="android:widgetLayout">@layout/preference_profiles_widget</item>
+ </style>
</resources>
diff --git a/res/xml/appgroup_list.xml b/res/xml/appgroup_list.xml
new file mode 100644
index 0000000..a578a19
--- /dev/null
+++ b/res/xml/appgroup_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="profile_appgroups_list"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+</PreferenceScreen>
diff --git a/res/xml/application_list.xml b/res/xml/application_list.xml
new file mode 100644
index 0000000..da8c201
--- /dev/null
+++ b/res/xml/application_list.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+ <PreferenceCategory
+ android:key="general_section"
+ android:title="@string/profile_appgroup_name_title">
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="applications_list"
+ android:title="@string/profile_applist_title" >
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/res/xml/dashboard_categories.xml b/res/xml/dashboard_categories.xml
index 6c617d7..202e0ff 100644
--- a/res/xml/dashboard_categories.xml
+++ b/res/xml/dashboard_categories.xml
@@ -177,6 +177,14 @@
android:key="@string/category_key_personal"
android:title="@string/header_category_personal" >
+ <!-- Profiles -->
+ <dashboard-tile
+ android:id="@+id/profile_settings"
+ android:fragment="com.android.settings.profiles.ProfilesSettings"
+ android:title="@string/profiles_settings_title"
+ android:icon="@drawable/ic_settings_location"
+ />
+
<!-- Location -->
<dashboard-tile
android:id="@+id/location_settings"
diff --git a/res/xml/profile_config.xml b/res/xml/profile_config.xml
new file mode 100644
index 0000000..6777a30
--- /dev/null
+++ b/res/xml/profile_config.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+ <PreferenceCategory
+ android:key="profile_general_section"
+ android:title="@string/profile_name_title">
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="profile_connectionoverrides"
+ android:title="@string/profile_connectionoverrides_title" />
+
+ <PreferenceCategory
+ android:key="profile_volumeoverrides"
+ android:title="@string/profile_volumeoverrides_title" />
+
+ <PreferenceCategory
+ android:key="profile_system_settings"
+ android:title="@string/profile_system_settings_title" />
+
+ <PreferenceCategory
+ android:key="profile_appgroups"
+ android:title="@string/profile_appgroups_title" />
+
+</PreferenceScreen>
diff --git a/res/xml/profile_settings.xml b/res/xml/profile_settings.xml
new file mode 100644
index 0000000..8bce716
--- /dev/null
+++ b/res/xml/profile_settings.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/profile_settings"
+ android:key="profile_settings"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
+
+ <ListPreference
+ android:key="sound_mode"
+ android:title="@string/sound_mode"
+ android:summary="@string/sound_mode"
+ android:entries="@array/profile_entries"
+ android:persistent="false"
+ android:entryValues="@array/profile_values" />
+
+ <com.android.settings.profiles.ProfileRingtonePreference
+ android:key="soundtone"
+ android:title="@string/soundtone_title"
+ android:summary="@string/soundtone_summary"
+ android:dialogTitle="@string/soundtone_title"
+ android:persistent="false"
+ android:ringtoneType="notification" />
+
+ <ListPreference
+ android:key="ringer_mode"
+ android:title="@string/ringer_mode"
+ android:summary="@string/ringer_mode"
+ android:entries="@array/profile_entries"
+ android:persistent="false"
+ android:entryValues="@array/profile_values" />
+
+ <com.android.settings.profiles.ProfileRingtonePreference
+ android:key="ringtone"
+ android:title="@string/ringtone_title"
+ android:summary="@string/ringtone_summary"
+ android:dialogTitle="@string/ringtone_title"
+ android:persistent="false"
+ android:ringtoneType="ringtone" />
+
+ <ListPreference
+ android:key="vibrate_mode"
+ android:title="@string/vibrate_mode"
+ android:summary="@string/sound_mode"
+ android:entries="@array/profile_entries"
+ android:persistent="false"
+ android:entryValues="@array/profile_values" />
+
+ <ListPreference
+ android:key="lights_mode"
+ android:title="@string/lights_mode"
+ android:summary="@string/sound_mode"
+ android:entries="@array/profile_entries"
+ android:persistent="false"
+ android:entryValues="@array/profile_values" />
+
+
+</PreferenceScreen>
diff --git a/res/xml/profiles_settings.xml b/res/xml/profiles_settings.xml
new file mode 100644
index 0000000..d3c477c
--- /dev/null
+++ b/res/xml/profiles_settings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+ android:key="profiles_list" />
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index b6d9414..0a09b15 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -84,6 +84,9 @@ import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
+import android.util.DisplayMetrics;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
import android.widget.ListView;
import android.widget.TabWidget;
@@ -155,6 +158,14 @@ public final class Utils {
private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>();
+ // Device types
+ private static final int DEVICE_PHONE = 0;
+ private static final int DEVICE_HYBRID = 1;
+ private static final int DEVICE_TABLET = 2;
+
+ // Device type reference
+ private static int sDeviceType = -1;
+
/**
* Finds a matching activity for a preference's intent. If a matching
* activity is not found, it will remove the preference.
@@ -609,6 +620,40 @@ public final class Utils {
.getUsers().size() > 1;
}
+ private static int getScreenType(Context context) {
+ if (sDeviceType == -1) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayInfo outDisplayInfo = new DisplayInfo();
+ wm.getDefaultDisplay().getDisplayInfo(outDisplayInfo);
+ int shortSize = Math.min(outDisplayInfo.logicalHeight, outDisplayInfo.logicalWidth);
+ int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT
+ / outDisplayInfo.logicalDensityDpi;
+ if (shortSizeDp < 600) {
+ // 0-599dp: "phone" UI with a separate status & navigation bar
+ sDeviceType = DEVICE_PHONE;
+ } else if (shortSizeDp < 720) {
+ // 600-719dp: "phone" UI with modifications for larger screens
+ sDeviceType = DEVICE_HYBRID;
+ } else {
+ // 720dp: "tablet" UI with a single combined status & navigation bar
+ sDeviceType = DEVICE_TABLET;
+ }
+ }
+ return sDeviceType;
+ }
+
+ public static boolean isPhone(Context context) {
+ return getScreenType(context) == DEVICE_PHONE;
+ }
+
+ public static boolean isHybrid(Context context) {
+ return getScreenType(context) == DEVICE_HYBRID;
+ }
+
+ public static boolean isTablet(Context context) {
+ return getScreenType(context) == DEVICE_TABLET;
+ }
+
/**
* Start a new instance of the activity, showing only the given fragment.
* When launched in this mode, the given preference fragment will be instantiated and fill the
diff --git a/src/com/android/settings/profiles/AbstractTriggerPreference.java b/src/com/android/settings/profiles/AbstractTriggerPreference.java
new file mode 100644
index 0000000..1bc2ec0
--- /dev/null
+++ b/src/com/android/settings/profiles/AbstractTriggerPreference.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.Profile;
+import android.content.Context;
+import android.preference.Preference;
+
+public class AbstractTriggerPreference extends Preference {
+
+ public AbstractTriggerPreference(Context context) {
+ super(context);
+ }
+
+ private int mTriggerState = Profile.TriggerState.DISABLED;
+
+ public void setTriggerState(int trigger) {
+ mTriggerState = trigger;
+ }
+
+ public int getTriggerState() {
+ return mTriggerState;
+ }
+}
diff --git a/src/com/android/settings/profiles/AppGroupConfig.java b/src/com/android/settings/profiles/AppGroupConfig.java
new file mode 100644
index 0000000..8fbcfd0
--- /dev/null
+++ b/src/com/android/settings/profiles/AppGroupConfig.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.NotificationGroup;
+import android.app.ProfileManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.Preference;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+public class AppGroupConfig extends SettingsPreferenceFragment
+ implements Preference.OnPreferenceChangeListener {
+
+ private static String TAG = "AppGroupConfig";
+
+ private static final int DIALOG_APPS = 0;
+
+ private static final int DELETE_CONFIRM = 1;
+
+ private static final int DELETE_GROUP_CONFIRM = 2;
+
+ public static final String PROFILE_SERVICE = "profile";
+
+ private ListView mListView;
+
+ private PackageManager mPackageManager;
+
+ private NotificationGroup mNotificationGroup;
+
+ private ProfileManager mProfileManager;
+
+ private NamePreference mNamePreference;
+
+ private static final int MENU_DELETE = Menu.FIRST;
+
+ private static final int MENU_ADD = Menu.FIRST + 1;
+
+ PackageAdaptor mAppAdapter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE);
+ addPreferencesFromResource(R.xml.application_list);
+
+ final Bundle args = getArguments();
+ if (args != null) {
+ mNotificationGroup = (NotificationGroup) args.getParcelable("NotificationGroup");
+ mPackageManager = getPackageManager();
+ mAppAdapter = new PackageAdaptor(mPackageManager.getInstalledPackages(0));
+ mAppAdapter.update();
+
+ updatePackages();
+
+ setHasOptionsMenu(true);
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ MenuItem delete = menu.add(0, MENU_DELETE, 0, R.string.profile_menu_delete)
+ .setIcon(R.drawable.ic_menu_trash_holo_dark);
+ delete.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ MenuItem addApplication = menu.add(0, MENU_ADD, 0, R.string.profiles_add)
+ .setIcon(R.drawable.ic_menu_add)
+ .setAlphabeticShortcut('a');
+ addApplication.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_DELETE:
+ deleteNotificationGroup();
+ return true;
+ case MENU_ADD:
+ addNewApp();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ Preference mAddPreference;
+
+ Preference mDeletePreference;
+
+ private void updatePackages() {
+ PreferenceScreen prefSet = getPreferenceScreen();
+
+ // Add the General section
+ PreferenceGroup generalPrefs = (PreferenceGroup) prefSet.findPreference("general_section");
+ if (generalPrefs != null) {
+ generalPrefs.removeAll();
+
+ // Name preference
+ mNamePreference = new NamePreference(getActivity(), mNotificationGroup.getName());
+ mNamePreference.setOnPreferenceChangeListener(this);
+ generalPrefs.addPreference(mNamePreference);
+ }
+
+ PreferenceGroup applicationsList = (PreferenceGroup) prefSet.findPreference("applications_list");
+ if (applicationsList != null) {
+ applicationsList.removeAll();
+ for (String pkg : mNotificationGroup.getPackages()) {
+ Preference pref = new Preference(getActivity());
+ try {
+ PackageInfo group = mPackageManager.getPackageInfo(pkg, 0);
+ pref.setKey(group.packageName);
+ pref.setTitle(group.applicationInfo.loadLabel(mPackageManager));
+ Drawable icon = group.applicationInfo.loadIcon(mPackageManager);
+ pref.setIcon(icon);
+ pref.setSelectable(true);
+ pref.setPersistent(false);
+ applicationsList.addPreference(pref);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ menu.add(0, R.string.profile_menu_delete, 0, R.string.profile_menu_delete);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo aMenuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+ PackageItem selectedGroup = (PackageItem) mListView.getItemAtPosition(aMenuInfo.position);
+ switch (item.getItemId()) {
+ case R.string.profile_menu_delete:
+ deleteAppFromGroup(selectedGroup);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void deleteAppFromGroup(PackageItem selectedGroup) {
+ if (selectedGroup != null) {
+ mNotificationGroup.removePackage(selectedGroup.packageName);
+ updatePackages();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ if (mNotificationGroup != null) {
+ mProfileManager.addNotificationGroup(mNotificationGroup);
+ }
+ super.onPause();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mNamePreference) {
+ String name = mNamePreference.getName().toString();
+ if (!name.equals(mNotificationGroup.getName())) {
+ if (!mProfileManager.notificationGroupExists(name)) {
+ mNotificationGroup.setName(name);
+ } else {
+ mNamePreference.setName(mNotificationGroup.getName());
+ Toast.makeText(getActivity(), R.string.duplicate_appgroup_name, Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference instanceof Preference) {
+ String deleteItem = preference.getKey();
+ removeApp(deleteItem);
+ return true;
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void addNewApp() {
+ showDialog(DIALOG_APPS);
+ // TODO: switch to using the built in app list rather than dialog box?
+ }
+
+ private void removeApp(String key) {
+ mPackageToDelete = key.toString();
+ showDialog(DELETE_CONFIRM);
+ }
+
+ private void deleteNotificationGroup() {
+ showDialog(DELETE_GROUP_CONFIRM);
+ }
+
+ @Override
+ public Dialog onCreateDialog(int id) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ final Dialog dialog;
+ switch (id) {
+ case DIALOG_APPS:
+ final ListView list = new ListView(getActivity());
+ list.setAdapter(mAppAdapter);
+ builder.setTitle(R.string.profile_choose_app);
+ builder.setView(list);
+ dialog = builder.create();
+ list.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ PackageItem info = (PackageItem) parent.getItemAtPosition(position);
+ mNotificationGroup.addPackage(info.packageName);
+ updatePackages();
+ dialog.cancel();
+ }
+ });
+ break;
+ case DELETE_CONFIRM:
+ builder.setMessage(R.string.profile_app_delete_confirm);
+ builder.setTitle(R.string.profile_menu_delete);
+ builder.setIconAttribute(android.R.attr.alertDialogIcon);
+ builder.setPositiveButton(android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ doDelete();
+ }
+ });
+ builder.setNegativeButton(android.R.string.no,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ dialog = builder.create();
+ break;
+ case DELETE_GROUP_CONFIRM:
+ builder.setMessage(R.string.profile_delete_appgroup);
+ builder.setTitle(R.string.profile_menu_delete);
+ builder.setIconAttribute(android.R.attr.alertDialogIcon);
+ builder.setPositiveButton(android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mProfileManager.removeNotificationGroup(mNotificationGroup);
+ mNotificationGroup = null;
+ finish();
+ }
+ });
+ builder.setNegativeButton(android.R.string.no,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ dialog = builder.create();
+ break;
+ default:
+ dialog = null;
+ }
+ return dialog;
+ }
+
+ String mPackageToDelete;
+
+ private void doDelete() {
+ mNotificationGroup.removePackage(mPackageToDelete);
+ updatePackages();
+ }
+
+ class PackageItem implements Comparable<PackageItem> {
+ String title;
+ String packageName;
+ Drawable icon;
+ boolean enabled;
+
+ @Override
+ public int compareTo(PackageItem another) {
+ if (enabled != another.enabled) {
+ return enabled ? -1 : 1;
+ }
+ int titleResult = title.compareToIgnoreCase(another.title);
+ if (titleResult != 0) {
+ return titleResult;
+ }
+ return packageName.compareTo(another.packageName);
+ }
+ }
+
+ class PackageAdaptor extends BaseAdapter {
+
+ protected List<PackageInfo> mInstalledPackageInfo;
+
+ protected List<PackageItem> mInstalledPackages = new LinkedList<PackageItem>();
+
+ private void reloadList() {
+ final Handler handler = new Handler();
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ synchronized (mInstalledPackages) {
+ mInstalledPackages.clear();
+ for (PackageInfo info : mInstalledPackageInfo) {
+ final PackageItem item = new PackageItem();
+ ApplicationInfo applicationInfo = info.applicationInfo;
+ item.title = applicationInfo.loadLabel(mPackageManager).toString();
+ item.icon = applicationInfo.loadIcon(mPackageManager);
+ item.packageName = applicationInfo.packageName;
+ item.enabled = applicationInfo.enabled;
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ int index = Collections.binarySearch(mInstalledPackages, item);
+ if (index < 0) {
+ index = -index - 1;
+ mInstalledPackages.add(index, item);
+ }
+ notifyDataSetChanged();
+ }
+ });
+ }
+ }
+ }
+ }).start();
+ }
+
+ public PackageAdaptor(List<PackageInfo> installedPackagesInfo) {
+ mInstalledPackageInfo = installedPackagesInfo;
+ }
+
+ public void update() {
+ reloadList();
+ }
+
+ @Override
+ public int getCount() {
+ return mInstalledPackages.size();
+ }
+
+ @Override
+ public PackageItem getItem(int position) {
+ return mInstalledPackages.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mInstalledPackages.get(position).packageName.hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+ if (convertView != null) {
+ holder = (ViewHolder) convertView.getTag();
+ } else {
+ final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = layoutInflater.inflate(R.layout.preference_icon, null, false);
+ holder = new ViewHolder();
+ convertView.setTag(holder);
+ holder.title = (TextView) convertView.findViewById(com.android.internal.R.id.title);
+ holder.summary = (TextView) convertView
+ .findViewById(com.android.internal.R.id.summary);
+ holder.icon = (ImageView) convertView.findViewById(R.id.icon);
+ }
+ PackageItem applicationInfo = getItem(position);
+
+ if (holder.title != null) {
+ holder.title.setText(applicationInfo.title);
+ }
+ if (holder.summary != null) {
+ holder.summary.setVisibility(View.GONE);
+ }
+ if (holder.icon != null) {
+ Drawable loadIcon = applicationInfo.icon;
+ holder.icon.setImageDrawable(loadIcon);
+ }
+ return convertView;
+ }
+ }
+
+ static class ViewHolder {
+ TextView title;
+ TextView summary;
+ ImageView icon;
+ }
+}
diff --git a/src/com/android/settings/profiles/AppGroupList.java b/src/com/android/settings/profiles/AppGroupList.java
new file mode 100644
index 0000000..088b344
--- /dev/null
+++ b/src/com/android/settings/profiles/AppGroupList.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.NotificationGroup;
+import android.app.ProfileManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+public class AppGroupList extends SettingsPreferenceFragment {
+
+ private static final String TAG = "AppGroupSettings";
+ public static final String PROFILE_SERVICE = "profile";
+
+ private ProfileManager mProfileManager;
+
+ // constant value that can be used to check return code from sub activity.
+ private static final int APP_GROUP_CONFIG = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.appgroup_list);
+ mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refreshList();
+
+ // On tablet devices remove the padding
+ if (Utils.isTablet(getActivity())) {
+ getListView().setPadding(0, 0, 0, 0);
+ }
+ }
+
+ public void refreshList() {
+ PreferenceScreen appgroupList = getPreferenceScreen();
+ appgroupList.removeAll();
+
+ // Add the existing app groups
+ for (NotificationGroup group : mProfileManager.getNotificationGroups()) {
+ PreferenceScreen pref = new PreferenceScreen(getActivity(), null);
+ pref.setKey(group.getUuid().toString());
+ pref.setTitle(group.getName());
+ pref.setPersistent(false);
+ appgroupList.addPreference(pref);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ if (preference instanceof PreferenceScreen) {
+ NotificationGroup group = mProfileManager.getNotificationGroup(
+ UUID.fromString(preference.getKey()));
+ editGroup(group);
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void editGroup(NotificationGroup group) {
+ Bundle args = new Bundle();
+ args.putParcelable("NotificationGroup", group);
+
+ SettingsActivity pa = (SettingsActivity) getActivity();
+ pa.startPreferencePanel(AppGroupConfig.class.getName(), args,
+ R.string.profile_appgroup_manage, null, this, APP_GROUP_CONFIG);
+ }
+}
diff --git a/src/com/android/settings/profiles/ApplicationItemPreference.java b/src/com/android/settings/profiles/ApplicationItemPreference.java
new file mode 100644
index 0000000..1247e85
--- /dev/null
+++ b/src/com/android/settings/profiles/ApplicationItemPreference.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import com.android.settings.R;
+
+public class ApplicationItemPreference extends Preference {
+
+ private static String TAG = "ApplicationItemPreference";
+
+ private Drawable mIcon;
+
+ public ApplicationItemPreference(Context context) {
+ this(context, null, 0);
+ }
+
+ public ApplicationItemPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setLayoutResource(R.layout.preference_icon);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.IconPreferenceScreen, defStyle, 0);
+ mIcon = a.getDrawable(R.styleable.IconPreferenceScreen_icon);
+ }
+
+ public void setIcon(Drawable icon){
+ mIcon = icon;
+ }
+
+ @Override
+ public void onBindView(View view) {
+ super.onBindView(view);
+
+ float valueDips = 36.0f;
+ final float scale = getContext().getResources().getDisplayMetrics().density;
+ int valuePixels = (int) (valueDips * scale + 0.5f);
+
+ ImageView imageView = (ImageView) view.findViewById(R.id.icon);
+ if (imageView != null && mIcon != null) {
+ imageView.setAdjustViewBounds(true);
+ imageView.setMaxHeight(valuePixels);
+ imageView.setMaxWidth(valuePixels);
+ imageView.setImageDrawable(mIcon);
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/BluetoothTriggerPreference.java b/src/com/android/settings/profiles/BluetoothTriggerPreference.java
new file mode 100644
index 0000000..848fc28
--- /dev/null
+++ b/src/com/android/settings/profiles/BluetoothTriggerPreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+
+public class BluetoothTriggerPreference extends AbstractTriggerPreference {
+
+ private String mAddress;
+
+ BluetoothTriggerPreference(Context context, BluetoothDevice device) {
+ super(context);
+ mAddress = device.getAddress();
+ if (device.getAlias() != null) {
+ setTitle(device.getAlias());
+ } else {
+ setTitle(device.getName());
+ }
+ }
+
+ BluetoothTriggerPreference(Context context, String name, String address) {
+ super(context);
+ mAddress = address;
+ setTitle(name);
+ }
+
+ public String getAddress() {
+ return mAddress;
+ }
+}
diff --git a/src/com/android/settings/profiles/NFCProfile.java b/src/com/android/settings/profiles/NFCProfile.java
new file mode 100644
index 0000000..a6e2334
--- /dev/null
+++ b/src/com/android/settings/profiles/NFCProfile.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.Activity;
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+/**
+ * This activity handles NDEF_DISCOVERED intents with the cm/profile mime type.
+ * Tags should be encoded with the 16-byte UUID of the profile to be activated.
+ * Tapping a tag while that profile is already active will select the previously
+ * active profile.
+ */
+public class NFCProfile extends Activity {
+
+ private static final String PREFS_NAME = "NFCProfile";
+
+ private static final String PREFS_PREVIOUS_PROFILE = "previous-profile";
+
+ static final String PROFILE_MIME_TYPE = "cm/profile";
+
+ private ProfileManager mProfileManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mProfileManager = (ProfileManager) getSystemService(Context.PROFILE_SERVICE);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ Intent intent = getIntent();
+ String action = intent.getAction();
+ if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
+ Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
+ if (rawMsgs != null) {
+ NdefMessage[] msgs = new NdefMessage[rawMsgs.length];
+ for (int i = 0; i < rawMsgs.length; i++) {
+ msgs[i] = (NdefMessage) rawMsgs[i];
+ for (NdefRecord record : msgs[i].getRecords()) {
+ String type = new String(record.getType());
+ byte[] payload = record.getPayload();
+ if (PROFILE_MIME_TYPE.equals(type) && payload != null
+ && payload.length == 16) {
+ handleProfileMimeType(payload);
+ }
+ }
+ }
+ }
+ }
+ finish();
+ }
+
+ private void handleProfileMimeType(byte[] payload) {
+ UUID profileUuid = NFCProfileUtils.toUUID(payload);
+
+ boolean enabled = Settings.System.getInt(getContentResolver(),
+ Settings.System.SYSTEM_PROFILES_ENABLED, 1) == 1;
+
+ if (enabled) {
+ // Only do NFC profile changing if System Profile support is enabled
+ Profile currentProfile = mProfileManager.getActiveProfile();
+ Profile targetProfile = mProfileManager.getProfile(profileUuid);
+
+ if (targetProfile == null) {
+ // show profile selection for unknown tag
+ Intent i = new Intent(this, NFCProfileSelect.class);
+ i.putExtra(NFCProfileSelect.EXTRA_PROFILE_UUID, profileUuid.toString());
+ i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ this.startActivity(i);
+ } else {
+ // switch to profile
+ if (currentProfile == null || !currentProfile.getUuid().equals(profileUuid)) {
+ saveCurrentProfile();
+ switchTo(profileUuid);
+ } else {
+ Profile lastProfile = getPreviouslySelectedProfile();
+ if (lastProfile != null) {
+ switchTo(lastProfile.getUuid());
+ clearPreviouslySelectedProfile();
+ }
+ }
+ }
+ }
+ }
+
+ private void switchTo(UUID uuid) {
+ Profile p = mProfileManager.getProfile(uuid);
+ if (p != null) {
+ mProfileManager.setActiveProfile(uuid);
+
+ Toast.makeText(
+ this,
+ getString(R.string.profile_selected, p.getName()),
+ Toast.LENGTH_LONG).show();
+ NFCProfileUtils.vibrate(this);
+ }
+ }
+
+ private Profile getPreviouslySelectedProfile() {
+ Profile previous = null;
+ SharedPreferences prefs = getSharedPreferences(PREFS_NAME, 0);
+ String uuid = prefs.getString(PREFS_PREVIOUS_PROFILE, null);
+ if (uuid != null) {
+ previous = mProfileManager.getProfile(UUID.fromString(uuid));
+ }
+ return previous;
+ }
+
+ private void clearPreviouslySelectedProfile() {
+ SharedPreferences.Editor editor = getSharedPreferences(PREFS_NAME, 0).edit();
+ editor.remove(PREFS_PREVIOUS_PROFILE);
+ editor.commit();
+ }
+
+ private void saveCurrentProfile() {
+ Profile currentProfile = mProfileManager.getActiveProfile();
+ if (currentProfile != null) {
+ SharedPreferences.Editor editor = getSharedPreferences(PREFS_NAME, 0).edit();
+ editor.putString(PREFS_PREVIOUS_PROFILE, currentProfile.getUuid().toString());
+ editor.commit();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/NFCProfileSelect.java b/src/com/android/settings/profiles/NFCProfileSelect.java
new file mode 100644
index 0000000..c66de64
--- /dev/null
+++ b/src/com/android/settings/profiles/NFCProfileSelect.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+/**
+ * Activity to support attaching a unknown NFC tag to an existing profile.
+ */
+public class NFCProfileSelect extends Activity {
+
+ private static final String TAG = "NFCProfileSelect";
+
+ static final String EXTRA_PROFILE_UUID = "PROFILE_UUID";
+
+ private ProfileManager mProfileManager;
+
+ private UUID mProfileUuid;
+
+ final static int defaultChoice = -1;
+
+ private int currentChoice = defaultChoice;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mProfileManager = (ProfileManager) getSystemService(Context.PROFILE_SERVICE);
+
+ setContentView(R.layout.nfc_select);
+ setTitle(R.string.profile_unknown_nfc_tag);
+
+ findViewById(R.id.add_tag).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showProfileSelectionDialog();
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ String profileUuid = getIntent().getStringExtra(EXTRA_PROFILE_UUID);
+ if (profileUuid != null) {
+ mProfileUuid = UUID.fromString(profileUuid);
+ } else {
+ finish();
+ }
+ }
+
+ void showProfileSelectionDialog() {
+ final Profile[] profiles = mProfileManager.getProfiles();
+ final String[] profileNames = new String[profiles.length];
+ for (int i = 0; i < profiles.length; i++) {
+ profileNames[i] = profiles[i].getName();
+ }
+
+ Builder builder = new Builder(this);
+ builder.setTitle(R.string.profile_settings_title);
+ builder.setSingleChoiceItems(profileNames, currentChoice, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ currentChoice = which;
+ }
+ });
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (currentChoice != defaultChoice) {
+ Profile profile = profiles[currentChoice];
+ profile.addSecondaryUuid(mProfileUuid);
+ mProfileManager.updateProfile(profile);
+ Toast.makeText(NFCProfileSelect.this, R.string.profile_write_success, Toast.LENGTH_LONG).show();
+ }
+ finish();
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ });
+ builder.show();
+ }
+}
diff --git a/src/com/android/settings/profiles/NFCProfileUtils.java b/src/com/android/settings/profiles/NFCProfileUtils.java
new file mode 100644
index 0000000..f6461d1
--- /dev/null
+++ b/src/com/android/settings/profiles/NFCProfileUtils.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import android.app.Profile;
+import android.content.Context;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.Tag;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.NdefFormatable;
+import android.os.Vibrator;
+import android.util.Log;
+
+public class NFCProfileUtils {
+
+ private static final String TAG = "NFCUtils";
+
+ private static final long[] VIBRATION_PATTERN = {
+ 0, 100, 10000
+ };
+
+ static void vibrate(Context context) {
+ Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(VIBRATION_PATTERN, -1);
+ }
+
+ /*
+ * Writes an NdefMessage to a NFC tag
+ */
+ static boolean writeTag(NdefMessage message, Tag tag) {
+ int size = message.toByteArray().length;
+ try {
+ Ndef ndef = Ndef.get(tag);
+ if (ndef != null) {
+ ndef.connect();
+ if (!ndef.isWritable()) {
+ Log.e(TAG, "Tag is not writable!");
+ return false;
+ }
+ if (ndef.getMaxSize() < size) {
+ Log.e(TAG,
+ "Tag exceeds max ndef message size! [" + size + " > "
+ + ndef.getMaxSize() + "]");
+ return false;
+ }
+ ndef.writeNdefMessage(message);
+ return true;
+ } else {
+ NdefFormatable format = NdefFormatable.get(tag);
+ if (format != null) {
+ try {
+ format.connect();
+ format.format(message);
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "Write error!", e);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Write error!", e);
+ return false;
+ }
+ }
+
+ /* Convert a 16-byte array to a UUID */
+ static UUID toUUID(byte[] byteArray) {
+
+ long msb = 0;
+ long lsb = 0;
+ for (int i = 0; i < 8; i++) {
+ msb = (msb << 8) | (byteArray[i] & 0xff);
+ }
+ for (int i = 8; i < 16; i++) {
+ lsb = (lsb << 8) | (byteArray[i] & 0xff);
+ }
+ UUID result = new UUID(msb, lsb);
+
+ return result;
+ }
+
+ /* Convert a UUID to a 16-byte array */
+ static byte[] asByteArray(UUID uuid) {
+ long msb = uuid.getMostSignificantBits();
+ long lsb = uuid.getLeastSignificantBits();
+ byte[] buffer = new byte[16];
+
+ for (int i = 0; i < 8; i++) {
+ buffer[i] = (byte) (msb >>> 8 * (7 - i));
+ }
+ for (int i = 8; i < 16; i++) {
+ buffer[i] = (byte) (lsb >>> 8 * (7 - i));
+ }
+
+ return buffer;
+ }
+
+ /*
+ * Convert a profiles into an NdefMessage. The profile UUID is 16 bytes and
+ * stored with the cm/profile mimetype
+ */
+ static NdefMessage getProfileAsNdef(Profile profile) {
+ byte[] profileBytes = NFCProfileUtils.asByteArray(profile.getUuid());
+
+ NdefRecord record = NdefRecord.createMime(NFCProfile.PROFILE_MIME_TYPE, profileBytes);
+ return new NdefMessage(new NdefRecord[] { record });
+ }
+}
diff --git a/src/com/android/settings/profiles/NFCProfileWriter.java b/src/com/android/settings/profiles/NFCProfileWriter.java
new file mode 100644
index 0000000..72b8c13
--- /dev/null
+++ b/src/com/android/settings/profiles/NFCProfileWriter.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+/**
+ * Activity to support writing a profile to an NFC tag.
+ * The mime type is "cm/profile" and the payload is the raw bytes of the profile's
+ * UUID. The payload was intentionally kept small to support writing on 46-byte tags.
+ */
+public class NFCProfileWriter extends Activity {
+
+ private static final String TAG = "NFCProfileWriter";
+
+ static final String EXTRA_PROFILE_UUID = "PROFILE_UUID";
+
+ private NfcAdapter mNfcAdapter;
+
+ private IntentFilter[] mWriteTagFilters;
+
+ private Profile mProfile;
+
+ private ProfileManager mProfileManager;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+ mProfileManager = (ProfileManager) getSystemService(Context.PROFILE_SERVICE);
+
+ setContentView(R.layout.nfc_writer);
+ setTitle(R.string.profile_write_nfc_tag);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ String profileUuid = getIntent().getStringExtra(EXTRA_PROFILE_UUID);
+ if (profileUuid != null) {
+ mProfile = mProfileManager.getProfile(UUID.fromString(profileUuid));
+ Log.d(TAG, "Profile to write: " + mProfile.getName());
+ enableTagWriteMode();
+ }
+ }
+
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ disableTagWriteMode();
+ }
+
+ private PendingIntent getPendingIntent() {
+ return PendingIntent.getActivity(this, 0,
+ new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
+ }
+
+ private void disableTagWriteMode() {
+ mNfcAdapter.disableForegroundDispatch(this);
+ }
+
+ private void enableTagWriteMode() {
+ IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
+ mWriteTagFilters = new IntentFilter[] {
+ tagDetected
+ };
+ mNfcAdapter.enableForegroundDispatch(this, getPendingIntent(), mWriteTagFilters, null);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ // Tag writing mode
+ if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
+ Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
+ if (NFCProfileUtils.writeTag(NFCProfileUtils.getProfileAsNdef(mProfile), detectedTag)) {
+ Toast.makeText(this, R.string.profile_write_success, Toast.LENGTH_LONG).show();
+ NFCProfileUtils.vibrate(this);
+ } else {
+ Toast.makeText(this, R.string.profile_write_failed, Toast.LENGTH_LONG).show();
+ }
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/NamePreference.java b/src/com/android/settings/profiles/NamePreference.java
new file mode 100644
index 0000000..7b48e0c
--- /dev/null
+++ b/src/com/android/settings/profiles/NamePreference.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.preference.Preference;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+public class NamePreference extends Preference implements
+ View.OnClickListener, Preference.OnPreferenceChangeListener {
+ private static final String TAG = NamePreference.class.getSimpleName();
+
+ private TextView mNameView;
+
+ private String mName;
+
+ /**
+ * @param context
+ * @param title
+ */
+ public NamePreference(Context context, String name) {
+ super(context);
+ mName = name.toString();
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public NamePreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public void onBindView(View view) {
+ super.onBindView(view);
+
+ View namePref = view.findViewById(R.id.name_pref);
+ if ((namePref != null) && namePref instanceof LinearLayout) {
+ namePref.setOnClickListener(this);
+ }
+
+ mNameView = (TextView) view.findViewById(R.id.title);
+
+ updatePreferenceViews();
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.preference_name);
+ }
+
+ public void setName(String name) {
+ mName = (name.toString());
+ updatePreferenceViews();
+ }
+
+ public String getName() {
+ return(mName.toString());
+ }
+
+ private void updatePreferenceViews() {
+ if (mNameView != null) {
+ mNameView.setText(mName.toString());
+ }
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if (v != null) {
+ Context context = getContext();
+ if (context != null) {
+ final EditText entry = new EditText(context);
+ entry.setSingleLine();
+ entry.setText(mName.toString());
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.rename_dialog_title);
+ builder.setMessage(R.string.rename_dialog_message);
+ builder.setView(entry, 34, 16, 34, 16);
+ builder.setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String value = entry.getText().toString();
+ mName = value.toString();
+ mNameView.setText(value.toString());
+ callChangeListener(this);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ ((TextView)dialog.findViewById(android.R.id.message)).setTextAppearance(context,
+ android.R.style.TextAppearance_DeviceDefault_Small);
+ }
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ callChangeListener(preference);
+ return false;
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileAirplaneModePreference.java b/src/com/android/settings/profiles/ProfileAirplaneModePreference.java
new file mode 100644
index 0000000..067e43b
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileAirplaneModePreference.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+
+public class ProfileAirplaneModePreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private CheckBox mCheckBox;
+
+ final static String TAG = "ProfileSilentModePreference";
+
+ private ProfileConfig.AirplaneModeItem mAirplaneModeItem;
+
+ final static int defaultChoice = -1;
+
+ private int currentChoice;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public ProfileAirplaneModePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public ProfileAirplaneModePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public ProfileAirplaneModePreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_checkbox);
+ if ((widget != null) && widget instanceof CheckBox) {
+ mCheckBox = (CheckBox) widget;
+ mCheckBox.setOnCheckedChangeListener(this);
+
+ mProtectFromCheckedChange = true;
+ mCheckBox.setChecked(isChecked());
+ mProtectFromCheckedChange = false;
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof LinearLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.preference_streamvolume);
+ }
+
+ public boolean isChecked() {
+ return mAirplaneModeItem != null && mAirplaneModeItem.mSettings.isOverride();
+ }
+
+ public void setAirplaneModeItem(ProfileConfig.AirplaneModeItem airplaneModeItem) {
+ mAirplaneModeItem = airplaneModeItem;
+
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mAirplaneModeItem.mSettings.isOverride());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ mAirplaneModeItem.mSettings.setOverride(isChecked);
+
+ callChangeListener(isChecked);
+ }
+
+ protected Dialog createAirplaneModeDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final String[] AirplaneModeValues = getContext().getResources().getStringArray(
+ R.array.profile_connection_values);
+
+ currentChoice = mAirplaneModeItem.mSettings.getValue();
+
+ builder.setTitle(R.string.profile_airplanemode_title);
+ builder.setSingleChoiceItems(R.array.profile_connection_entries, currentChoice,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ currentChoice = item;
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if (currentChoice != defaultChoice) {
+ int value = Integer.parseInt(AirplaneModeValues[currentChoice]);
+ mAirplaneModeItem.mSettings.setValue(currentChoice);
+ setSummary(value == 1 ? getContext().getString(R.string.connection_state_enabled) : getContext()
+ .getString(R.string.connection_state_disabled));
+ }
+ }
+ });
+
+ builder.setNegativeButton(android.R.string.cancel, null);
+ return builder.create();
+ }
+
+ public ProfileConfig.AirplaneModeItem getAirplaneModeItem() {
+ return mAirplaneModeItem;
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ createAirplaneModeDialog().show();
+ }
+ }
+
+ public void setSummary(Context context) {
+ int value = mAirplaneModeItem.mSettings.getValue();
+ setSummary(value == 1 ? getContext().getString(R.string.connection_state_enabled) : getContext().getString(
+ R.string.connection_state_disabled));
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileConfig.java b/src/com/android/settings/profiles/ProfileConfig.java
new file mode 100644
index 0000000..3532720
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileConfig.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+import android.app.AirplaneModeSettings;
+import android.app.AlertDialog;
+import android.app.ConnectionSettings;
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
+import android.app.RingModeSettings;
+import android.app.StreamSettings;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.net.wimax.WimaxHelper;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import static com.android.settings.profiles.ProfilesUtils.*;
+import com.android.settings.SettingsPreferenceFragment;
+
+public class ProfileConfig extends SettingsPreferenceFragment
+ implements Preference.OnPreferenceChangeListener {
+
+ static final String TAG = "ProfileConfig";
+
+ public static final String PROFILE_SERVICE = "profile";
+
+ private ProfileManager mProfileManager;
+
+ private static final int MENU_NFC_WRITE = Menu.FIRST;
+
+ private static final int MENU_DELETE = Menu.FIRST + 1;
+
+ private static final int MENU_TRIGGERS = Menu.FIRST + 2;
+
+ private Profile mProfile;
+
+ private NamePreference mNamePreference;
+
+ private ListPreference mScreenLockModePreference;
+
+ // constant value that can be used to check return code from sub activity.
+ private static final int PROFILE_GROUP_DETAILS = 1;
+
+ private StreamItem[] mStreams;
+
+ private ArrayList<ConnectionItem> mConnections;
+
+ private RingModeItem mRingMode;
+
+ private AirplaneModeItem mAirplaneMode;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mStreams = new StreamItem[] {
+ new StreamItem(AudioManager.STREAM_ALARM, getString(R.string.alarm_volume_title)),
+ new StreamItem(AudioManager.STREAM_MUSIC, getString(R.string.media_volume_title)),
+ new StreamItem(AudioManager.STREAM_RING, getString(R.string.incoming_call_volume_title)),
+ new StreamItem(AudioManager.STREAM_NOTIFICATION, getString(R.string.notification_volume_title))
+ };
+
+ mConnections = new ArrayList<ConnectionItem>();
+ if (deviceSupportsBluetooth()) {
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_BLUETOOTH, getString(R.string.toggleBluetooth)));
+ }
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_GPS, getString(R.string.toggleGPS)));
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_WIFI, getString(R.string.toggleWifi)));
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_SYNC, getString(R.string.toggleSync)));
+ if (deviceSupportsMobileData(getActivity())) {
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_MOBILEDATA, getString(R.string.toggleData)));
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_WIFIAP, getString(R.string.toggleWifiAp)));
+ final TelephonyManager tm = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
+ if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_2G3G, getString(R.string.toggle2g3g), R.array.profile_networkmode_entries));
+ }
+ }
+ if (WimaxHelper.isWimaxSupported(getActivity())) {
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_WIMAX, getString(R.string.toggleWimax)));
+ }
+ if (deviceSupportsNfc(getActivity())) {
+ mConnections.add(new ConnectionItem(ConnectionSettings.PROFILE_CONNECTION_NFC, getString(R.string.toggleNfc)));
+ }
+
+ addPreferencesFromResource(R.xml.profile_config);
+
+ mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE);
+
+ final Bundle args = getArguments();
+ mProfile = (args != null) ? (Profile) args.getParcelable("Profile") : null;
+
+ if (mProfile == null) {
+ mProfile = new Profile(getString(R.string.new_profile_name));
+ mProfileManager.addProfile(mProfile);
+ }
+
+ setHasOptionsMenu(true);
+
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ if (deviceSupportsNfc(getActivity())) {
+ MenuItem nfc = menu.add(0, MENU_NFC_WRITE, 0, R.string.profile_write_nfc_tag)
+ .setIcon(R.drawable.ic_menu_nfc_writer_dark);
+ nfc.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
+ MenuItem triggers = menu.add(0, MENU_TRIGGERS, 0, R.string.profile_triggers)
+ .setIcon(R.drawable.ic_location);
+ triggers.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ MenuItem delete = menu.add(0, MENU_DELETE, 1, R.string.profile_menu_delete)
+ .setIcon(R.drawable.ic_menu_trash_holo_dark);
+ delete.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_DELETE:
+ deleteProfile();
+ return true;
+ case MENU_NFC_WRITE:
+ startNFCProfileWriter();
+ return true;
+ case MENU_TRIGGERS:
+ startTriggerFragment();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mProfile = mProfileManager.getProfile(mProfile.getUuid());
+ fillList();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // Save profile here
+ if (mProfile != null) {
+ mProfileManager.updateProfile(mProfile);
+ }
+ }
+
+ private void startNFCProfileWriter() {
+ SettingsActivity pa = (SettingsActivity) getActivity();
+ Intent i = new Intent(this.getActivity(), NFCProfileWriter.class);
+ i.putExtra(NFCProfileWriter.EXTRA_PROFILE_UUID, mProfile.getUuid().toString());
+ i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ pa.startActivity(i);
+ }
+
+ private void startTriggerFragment() {
+ final SettingsActivity pa = (SettingsActivity) getActivity();
+ final Bundle args = new Bundle();
+ args.putParcelable("profile", mProfile);
+
+ pa.startPreferencePanel(TriggersFragment.class.getName(), args, 0, "", null, 0);
+ }
+
+ private void fillList() {
+ PreferenceScreen prefSet = getPreferenceScreen();
+
+ // Add the General section
+ PreferenceGroup generalPrefs = (PreferenceGroup) prefSet.findPreference("profile_general_section");
+ if (generalPrefs != null) {
+ generalPrefs.removeAll();
+
+ // Name preference
+ mNamePreference = new NamePreference(getActivity(), mProfile.getName());
+ mNamePreference.setOnPreferenceChangeListener(this);
+ generalPrefs.addPreference(mNamePreference);
+ }
+
+ // Populate system settings
+ PreferenceGroup systemPrefs = (PreferenceGroup) prefSet.findPreference("profile_system_settings");
+ if (systemPrefs != null) {
+ systemPrefs.removeAll();
+ // Ring mode preference
+ if (mRingMode == null) {
+ mRingMode = new RingModeItem();
+ }
+ RingModeSettings rms = mProfile.getRingMode();
+ if (rms == null) {
+ rms = new RingModeSettings();
+ mProfile.setRingMode(rms);
+ }
+ mRingMode.mSettings = rms;
+ ProfileRingModePreference rmp = new ProfileRingModePreference(getActivity());
+ rmp.setRingModeItem(mRingMode);
+ rmp.setTitle(R.string.ring_mode_title);
+ rmp.setPersistent(false);
+ rmp.setSummary(getActivity());
+ rmp.setOnPreferenceChangeListener(this);
+ mRingMode.mCheckbox = rmp;
+ systemPrefs.addPreference(rmp);
+
+ // Airplane mode preference
+ if (mAirplaneMode == null) {
+ mAirplaneMode = new AirplaneModeItem();
+ }
+ AirplaneModeSettings ams = mProfile.getAirplaneMode();
+ if (ams == null) {
+ ams = new AirplaneModeSettings();
+ mProfile.setAirplaneMode(ams);
+ }
+ mAirplaneMode.mSettings = ams;
+ ProfileAirplaneModePreference amp = new ProfileAirplaneModePreference(getActivity());
+ amp.setAirplaneModeItem(mAirplaneMode);
+ amp.setTitle(R.string.profile_airplanemode_title);
+ amp.setPersistent(false);
+ amp.setSummary(getActivity());
+ amp.setOnPreferenceChangeListener(this);
+ mAirplaneMode.mCheckbox = amp;
+ systemPrefs.addPreference(amp);
+
+ // Lockscreen mode preference
+ mScreenLockModePreference = new ListPreference(getActivity());
+ mScreenLockModePreference.setTitle(R.string.profile_lockmode_title);
+ mScreenLockModePreference.setEntries(R.array.profile_lockmode_entries);
+ mScreenLockModePreference.setEntryValues(R.array.profile_lockmode_values);
+ mScreenLockModePreference.setPersistent(false);
+ mScreenLockModePreference.setSummary(getResources().getStringArray(
+ R.array.profile_lockmode_summaries)[mProfile.getScreenLockMode()]);
+ mScreenLockModePreference.setValue(String.valueOf(mProfile.getScreenLockMode()));
+ mScreenLockModePreference.setOnPreferenceChangeListener(this);
+
+ // DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ // if (dpm.requireSecureKeyguard()) {
+ // mScreenLockModePreference.setEnabled(false);
+ // mScreenLockModePreference.setSummary(R.string.unlock_set_unlock_disabled_summary);
+ // }
+
+ systemPrefs.addPreference(mScreenLockModePreference);
+ }
+
+ // Populate the audio streams list
+ final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ PreferenceGroup streamList = (PreferenceGroup) prefSet.findPreference("profile_volumeoverrides");
+ if (streamList != null) {
+ streamList.removeAll();
+ for (StreamItem stream : mStreams) {
+ StreamSettings settings = mProfile.getSettingsForStream(stream.mStreamId);
+ if (settings == null) {
+ settings = new StreamSettings(stream.mStreamId);
+ mProfile.setStreamSettings(settings);
+ }
+ stream.mSettings = settings;
+ StreamVolumePreference pref = new StreamVolumePreference(getActivity());
+ pref.setKey("stream_" + stream.mStreamId);
+ pref.setTitle(stream.mLabel);
+ pref.setSummary(getString(R.string.volume_override_summary) + " " + settings.getValue()
+ + "/" + am.getStreamMaxVolume(stream.mStreamId));
+ pref.setPersistent(false);
+ pref.setStreamItem(stream);
+ stream.mCheckbox = pref;
+ streamList.addPreference(pref);
+ }
+ }
+
+ // Populate Connections list
+ PreferenceGroup connectionList = (PreferenceGroup) prefSet.findPreference("profile_connectionoverrides");
+ if (connectionList != null) {
+ connectionList.removeAll();
+ for (ConnectionItem connection : mConnections) {
+ String[] connectionstrings = getResources().getStringArray(connection.mChoices);
+ ConnectionSettings settings = mProfile.getSettingsForConnection(connection.mConnectionId);
+ if (settings == null) {
+ settings = new ConnectionSettings(connection.mConnectionId);
+ mProfile.setConnectionSettings(settings);
+ }
+ connection.mSettings = settings;
+ ProfileConnectionPreference pref = new ProfileConnectionPreference(getActivity());
+ pref.setKey("connection_" + connection.mConnectionId);
+ pref.setTitle(connection.mLabel);
+ pref.setSummary(connectionstrings[settings.getValue()]);
+ pref.setPersistent(false);
+ pref.setConnectionItem(connection);
+ connection.mCheckbox = pref;
+ connectionList.addPreference(pref);
+ }
+ }
+
+ // Populate Application groups
+ PreferenceGroup groupList = (PreferenceGroup) prefSet.findPreference("profile_appgroups");
+ if (groupList != null) {
+ groupList.removeAll();
+ for (ProfileGroup profileGroup : mProfile.getProfileGroups()) {
+ PreferenceScreen pref = new PreferenceScreen(getActivity(), null);
+ UUID uuid = profileGroup.getUuid();
+ pref.setKey(uuid.toString());
+ pref.setTitle(mProfileManager.getNotificationGroup(uuid).getName());
+ //pref.setSummary(R.string.profile_summary); // summary is repetitive, consider removing
+ pref.setPersistent(false);
+ pref.setSelectable(true);
+ groupList.addPreference(pref);
+ }
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference instanceof StreamVolumePreference) {
+ for (StreamItem stream : mStreams) {
+ if (preference == stream.mCheckbox) {
+ stream.mSettings.setOverride((Boolean) newValue);
+ }
+ }
+ } else if (preference instanceof ProfileConnectionPreference) {
+ for (ConnectionItem connection : mConnections) {
+ if (preference == connection.mCheckbox) {
+ connection.mSettings.setOverride((Boolean) newValue);
+ }
+ }
+ } else if (preference == mRingMode.mCheckbox) {
+ mRingMode.mSettings.setOverride((Boolean) newValue);
+ } else if (preference == mAirplaneMode.mCheckbox) {
+ mAirplaneMode.mSettings.setOverride((Boolean) newValue);
+ } else if (preference == mNamePreference) {
+ String name = mNamePreference.getName().toString();
+ if (!name.equals(mProfile.getName())) {
+ if (!mProfileManager.profileExists(name)) {
+ mProfile.setName(name);
+ } else {
+ mNamePreference.setName(mProfile.getName());
+ Toast.makeText(getActivity(), R.string.duplicate_profile_name, Toast.LENGTH_LONG).show();
+ }
+ }
+ } else if (preference == mScreenLockModePreference) {
+ mProfile.setScreenLockMode(Integer.valueOf((String) newValue));
+ mScreenLockModePreference.setSummary(getResources().getStringArray(
+ R.array.profile_lockmode_summaries)[mProfile.getScreenLockMode()]);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ Log.d(TAG, "onPreferenceTreeClick(): entered" + preferenceScreen.getKey() + preference.getKey());
+ if (preference instanceof PreferenceScreen) {
+ startProfileGroupActivity(preference.getKey(), preference.getTitle().toString());
+ return true;
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, preference);
+ }
+
+ private void startProfileGroupActivity(String key, String title) {
+ Bundle args = new Bundle();
+ args.putString("ProfileGroup", key.toString());
+ args.putParcelable("Profile", mProfile);
+
+ String header = mProfile.getName().toString() + ": " + title.toString();
+ SettingsActivity pa = (SettingsActivity) getActivity();
+ pa.startPreferencePanel(ProfileGroupConfig.class.getName(), args,
+ 0, header, this, PROFILE_GROUP_DETAILS);
+ }
+
+
+ private void deleteProfile() {
+ if (mProfile.getUuid().equals(mProfileManager.getActiveProfile().getUuid())) {
+ Toast toast = Toast.makeText(getActivity(), getString(R.string.profile_cannot_delete),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ } else {
+ AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
+ alert.setTitle(R.string.profile_menu_delete);
+ alert.setIconAttribute(android.R.attr.alertDialogIcon);
+ alert.setMessage(R.string.profile_delete_confirm);
+ alert.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ doDelete();
+ }
+ });
+ alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ alert.create().show();
+ }
+ }
+
+ private void doDelete() {
+ mProfileManager.removeProfile(mProfile);
+ mProfile = null;
+ finish();
+ }
+
+ static class StreamItem {
+ int mStreamId;
+ String mLabel;
+ StreamSettings mSettings;
+ StreamVolumePreference mCheckbox;
+
+ public StreamItem(int streamId, String label) {
+ mStreamId = streamId;
+ mLabel = label;
+ }
+ }
+
+ static class ConnectionItem {
+ int mConnectionId;
+ String mLabel;
+ ConnectionSettings mSettings;
+ ProfileConnectionPreference mCheckbox;
+ int mChoices;
+
+ public ConnectionItem(int connectionId, String label) {
+ mConnectionId = connectionId;
+ mChoices = R.array.profile_connection_entries;
+ mLabel = label;
+ }
+
+ public ConnectionItem(int connectionId, String label, int choices) {
+ mConnectionId = connectionId;
+ mLabel = label;
+ mChoices = choices;
+ }
+ }
+
+ static class RingModeItem {
+ RingModeSettings mSettings;
+ ProfileRingModePreference mCheckbox;
+
+ public RingModeItem() {
+ // nothing to do
+ }
+ }
+
+ static class AirplaneModeItem {
+ AirplaneModeSettings mSettings;
+ ProfileAirplaneModePreference mCheckbox;
+
+ public AirplaneModeItem() {
+ // nothing to do
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileConnectionPreference.java b/src/com/android/settings/profiles/ProfileConnectionPreference.java
new file mode 100644
index 0000000..a5fc986
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileConnectionPreference.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+
+public class ProfileConnectionPreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private CheckBox mCheckBox;
+
+ final static String TAG = "ProfileConnectionPreference";
+
+ private ProfileConfig.ConnectionItem mConnectionItem;
+
+ final static int defaultChoice = -1;
+
+ private int currentChoice;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public ProfileConnectionPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public ProfileConnectionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public ProfileConnectionPreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_checkbox);
+ if ((widget != null) && widget instanceof CheckBox) {
+ mCheckBox = (CheckBox) widget;
+ mCheckBox.setOnCheckedChangeListener(this);
+
+ mProtectFromCheckedChange = true;
+ mCheckBox.setChecked(isChecked());
+ mProtectFromCheckedChange = false;
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof LinearLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.preference_streamvolume);
+ }
+
+ public boolean isChecked() {
+ return mConnectionItem != null && mConnectionItem.mSettings.isOverride();
+ }
+
+ public void setConnectionItem(ProfileConfig.ConnectionItem connectionItem) {
+ mConnectionItem = connectionItem;
+
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mConnectionItem.mSettings.isOverride());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ mConnectionItem.mSettings.setOverride(isChecked);
+
+ callChangeListener(isChecked);
+ }
+
+ protected Dialog createConnectionDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final String[] ConnectionValues = getContext().getResources().getStringArray(R.array.profile_connection_values);
+ final String[] connectionNames = getContext().getResources().getStringArray(mConnectionItem.mChoices);
+
+ currentChoice = mConnectionItem.mSettings.getValue();
+
+ builder.setTitle(mConnectionItem.mLabel);
+ builder.setSingleChoiceItems(mConnectionItem.mChoices, currentChoice, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ currentChoice = item;
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if (currentChoice != defaultChoice) {
+ int value = Integer.parseInt(ConnectionValues[currentChoice]);
+ mConnectionItem.mSettings.setValue(value);
+ setSummary(connectionNames[value]);
+ }
+ }
+ });
+
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ }
+ });
+ return builder.create();
+ }
+
+ public ProfileConfig.ConnectionItem getConnectionItem() {
+ return mConnectionItem;
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ createConnectionDialog().show();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileEnabler.java b/src/com/android/settings/profiles/ProfileEnabler.java
new file mode 100644
index 0000000..0540dbe
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileEnabler.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.ProfileManager;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+
+public class ProfileEnabler implements CompoundButton.OnCheckedChangeListener {
+ private final Context mContext;
+ private Switch mSwitch;
+ private boolean mStateMachineEvent;
+
+ public ProfileEnabler(Context context, Switch switch_) {
+ mContext = context;
+ mSwitch = switch_;
+ }
+
+ public void resume() {
+ mSwitch.setOnCheckedChangeListener(this);
+ setSwitchState();
+ }
+
+ public void pause() {
+ mSwitch.setOnCheckedChangeListener(null);
+ }
+
+ public void setSwitch(Switch switch_) {
+ if (mSwitch == switch_) return;
+ mSwitch.setOnCheckedChangeListener(null);
+ mSwitch = switch_;
+ mSwitch.setOnCheckedChangeListener(this);
+ setSwitchState();
+ }
+
+ private void setSwitchState() {
+ boolean enabled = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.SYSTEM_PROFILES_ENABLED, 1) == 1;
+ mStateMachineEvent = true;
+ mSwitch.setChecked(enabled);
+ mStateMachineEvent = false;
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mStateMachineEvent) {
+ return;
+ }
+ // Handle a switch change
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SYSTEM_PROFILES_ENABLED, isChecked ? 1 : 0);
+
+ // Send a broadcast intent to the world
+ // TODO Enabling or disabling profiles should be at ProfileManager, not here
+ Intent intent=new Intent(ProfileManager.PROFILES_STATE_CHANGED_ACTION);
+ intent.putExtra(
+ ProfileManager.EXTRA_PROFILES_STATE,
+ isChecked ?
+ ProfileManager.PROFILES_STATE_ENABLED :
+ ProfileManager.PROFILES_STATE_DISABLED);
+ mContext.sendBroadcast(intent);
+
+ }
+
+}
diff --git a/src/com/android/settings/profiles/ProfileGroupConfig.java b/src/com/android/settings/profiles/ProfileGroupConfig.java
new file mode 100644
index 0000000..f1d4e7b
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileGroupConfig.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileGroup.Mode;
+import android.app.ProfileManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+public class ProfileGroupConfig extends SettingsPreferenceFragment implements
+ OnPreferenceChangeListener {
+
+ public static final String PROFILE_SERVICE = "profile";
+
+ private static final CharSequence KEY_SOUNDMODE = "sound_mode";
+
+ private static final CharSequence KEY_VIBRATEMODE = "vibrate_mode";
+
+ private static final CharSequence KEY_LIGHTSMODE = "lights_mode";
+
+ private static final CharSequence KEY_RINGERMODE = "ringer_mode";
+
+ private static final CharSequence KEY_SOUNDTONE = "soundtone";
+
+ private static final CharSequence KEY_RINGTONE = "ringtone";
+
+ Profile mProfile;
+
+ ProfileGroup mProfileGroup;
+
+ private ListPreference mSoundMode;
+
+ private ListPreference mRingerMode;
+
+ private ListPreference mVibrateMode;
+
+ private ListPreference mLightsMode;
+
+ private ProfileRingtonePreference mRingTone;
+
+ private ProfileRingtonePreference mSoundTone;
+
+ private ProfileManager mProfileManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.profile_settings);
+
+ final Bundle args = getArguments();
+ if (args != null) {
+ mProfile = (Profile) args.getParcelable("Profile");
+ UUID uuid = UUID.fromString(args.getString("ProfileGroup"));
+
+ mProfileManager = (ProfileManager) getSystemService(PROFILE_SERVICE);
+ mProfileGroup = mProfile.getProfileGroup(uuid);
+
+ mRingerMode = (ListPreference) findPreference(KEY_RINGERMODE);
+ mSoundMode = (ListPreference) findPreference(KEY_SOUNDMODE);
+ mVibrateMode = (ListPreference) findPreference(KEY_VIBRATEMODE);
+ mLightsMode = (ListPreference) findPreference(KEY_LIGHTSMODE);
+ mRingTone = (ProfileRingtonePreference) findPreference(KEY_RINGTONE);
+ mSoundTone = (ProfileRingtonePreference) findPreference(KEY_SOUNDTONE);
+
+ mRingTone.setShowSilent(false);
+ mSoundTone.setShowSilent(false);
+
+ mSoundMode.setOnPreferenceChangeListener(this);
+ mRingerMode.setOnPreferenceChangeListener(this);
+ mVibrateMode.setOnPreferenceChangeListener(this);
+ mLightsMode.setOnPreferenceChangeListener(this);
+ mSoundTone.setOnPreferenceChangeListener(this);
+ mRingTone.setOnPreferenceChangeListener(this);
+
+ updateState();
+ }
+ }
+
+ private void updateState() {
+
+ mVibrateMode.setValue(mProfileGroup.getVibrateMode().name());
+ mSoundMode.setValue(mProfileGroup.getSoundMode().name());
+ mRingerMode.setValue(mProfileGroup.getRingerMode().name());
+ mLightsMode.setValue(mProfileGroup.getLightsMode().name());
+
+ mVibrateMode.setSummary(mVibrateMode.getEntry());
+ mSoundMode.setSummary(mSoundMode.getEntry());
+ mRingerMode.setSummary(mRingerMode.getEntry());
+ mLightsMode.setSummary(mLightsMode.getEntry());
+
+ if (mProfileGroup.getSoundOverride() != null) {
+ mSoundTone.setRingtone(mProfileGroup.getSoundOverride());
+ }
+
+ if (mProfileGroup.getRingerOverride() != null) {
+ mRingTone.setRingtone(mProfileGroup.getRingerOverride());
+ }
+
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mVibrateMode) {
+ mProfileGroup.setVibrateMode(Mode.valueOf((String) newValue));
+ } else if (preference == mSoundMode) {
+ mProfileGroup.setSoundMode(Mode.valueOf((String) newValue));
+ } else if (preference == mRingerMode) {
+ mProfileGroup.setRingerMode(Mode.valueOf((String) newValue));
+ } else if (preference == mLightsMode) {
+ mProfileGroup.setLightsMode(Mode.valueOf((String) newValue));
+ } else if (preference == mRingTone) {
+ Uri uri = Uri.parse((String) newValue);
+ mProfileGroup.setRingerOverride(uri);
+ } else if (preference == mSoundTone) {
+ Uri uri = Uri.parse((String) newValue);
+ mProfileGroup.setSoundOverride(uri);
+ }
+
+ mProfileManager.updateProfile(mProfile);
+
+ updateState();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileRingModePreference.java b/src/com/android/settings/profiles/ProfileRingModePreference.java
new file mode 100644
index 0000000..d471998
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileRingModePreference.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+
+import com.android.settings.R;
+
+public class ProfileRingModePreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private CheckBox mCheckBox;
+
+ final static String TAG = "ProfileRingModePreference";
+
+ private ProfileConfig.RingModeItem mRingModeItem;
+
+ final static int defaultChoice = -1;
+
+ private int currentChoice;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public ProfileRingModePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public ProfileRingModePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public ProfileRingModePreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_checkbox);
+ if ((widget != null) && widget instanceof CheckBox) {
+ mCheckBox = (CheckBox) widget;
+ mCheckBox.setOnCheckedChangeListener(this);
+
+ mProtectFromCheckedChange = true;
+ mCheckBox.setChecked(isChecked());
+ mProtectFromCheckedChange = false;
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof LinearLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.preference_streamvolume);
+ }
+
+ public boolean isChecked() {
+ return mRingModeItem != null && mRingModeItem.mSettings.isOverride();
+ }
+
+ public void setRingModeItem(ProfileConfig.RingModeItem ringModeItem) {
+ mRingModeItem = ringModeItem;
+
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mRingModeItem.mSettings.isOverride());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ mRingModeItem.mSettings.setOverride(isChecked);
+
+ callChangeListener(isChecked);
+ }
+
+ protected Dialog createRingModeDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final String[] ringModeValues = getContext().getResources().getStringArray(R.array.ring_mode_values);
+ String currentValue = mRingModeItem.mSettings.getValue();
+ if (currentValue != null) {
+ for (int i = 0; i < ringModeValues.length; i++) {
+ if (currentValue.equals(ringModeValues[i])) {
+ currentChoice = i;
+ break;
+ }
+ }
+ }
+
+ builder.setTitle(R.string.ring_mode_title);
+ builder.setSingleChoiceItems(R.array.ring_mode_entries, currentChoice, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ currentChoice = item;
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int item) {
+ if (currentChoice != defaultChoice) {
+ String value = ringModeValues[currentChoice];
+ mRingModeItem.mSettings.setValue(value);
+ setSummary(getContext().getResources().getStringArray(R.array.ring_mode_entries)[currentChoice]);
+ }
+ }
+ });
+
+ builder.setNegativeButton(android.R.string.cancel, null);
+ return builder.create();
+ }
+
+ public ProfileConfig.RingModeItem getRingModeItem() {
+ return mRingModeItem;
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ createRingModeDialog().show();
+ }
+ }
+
+ public void setSummary(Context context) {
+ String[] entries = context.getResources().getStringArray(R.array.ring_mode_entries);
+ String[] values = context.getResources().getStringArray(R.array.ring_mode_values);
+ int l = entries.length;
+ String value = mRingModeItem.mSettings.getValue();
+ for (int i = 0; i < l; i++) {
+ if (value.equals(values[i])) {
+ setSummary(entries[i]);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfileRingtonePreference.java b/src/com/android/settings/profiles/ProfileRingtonePreference.java
new file mode 100644
index 0000000..91ccbe6
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfileRingtonePreference.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.preference.RingtonePreference;
+import android.util.AttributeSet;
+
+public class ProfileRingtonePreference extends RingtonePreference {
+ private static final String TAG = "ProfileRingtonePreference";
+
+ public ProfileRingtonePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) {
+ super.onPrepareRingtonePickerIntent(ringtonePickerIntent);
+
+ /*
+ * Since this preference is for choosing the default ringtone, it
+ * doesn't make sense to show a 'Default' item.
+ */
+ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
+ }
+
+ private Uri mRingtone;
+
+ void setRingtone(Uri uri) {
+ mRingtone = uri;
+ }
+
+ @Override
+ protected Uri onRestoreRingtone() {
+ if (mRingtone == null) {
+ return super.onRestoreRingtone();
+ } else {
+ return mRingtone;
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfilesList.java b/src/com/android/settings/profiles/ProfilesList.java
new file mode 100644
index 0000000..13fa16b
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfilesList.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import java.util.UUID;
+
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+public class ProfilesList extends SettingsPreferenceFragment implements
+ Preference.OnPreferenceChangeListener {
+ static final String TAG = "ProfilesSettings";
+ public static final String PROFILE_SERVICE = "profile";
+
+ private ProfileManager mProfileManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.profiles_settings);
+ mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refreshList();
+
+ // On tablet devices remove the padding
+ if (Utils.isTablet(getActivity())) {
+ getListView().setPadding(0, 0, 0, 0);
+ }
+ }
+
+ public void refreshList() {
+ PreferenceScreen plist = getPreferenceScreen();
+ plist.removeAll();
+
+ // Get active profile, if null
+ Profile prof = mProfileManager.getActiveProfile();
+ String selectedKey = prof != null ? prof.getUuid().toString() : null;
+
+ for (Profile profile : mProfileManager.getProfiles()) {
+ Bundle args = new Bundle();
+ args.putParcelable("Profile", profile);
+
+ ProfilesPreference ppref = new ProfilesPreference(this, args);
+ ppref.setKey(profile.getUuid().toString());
+ ppref.setTitle(profile.getName());
+ ppref.setPersistent(false);
+ ppref.setOnPreferenceChangeListener(this);
+ ppref.setSelectable(true);
+ ppref.setEnabled(true);
+
+ if (TextUtils.equals(selectedKey, ppref.getKey())) {
+ ppref.setChecked(true);
+ }
+
+ plist.addPreference(ppref);
+ }
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (newValue instanceof String) {
+ setSelectedProfile((String) newValue);
+ refreshList();
+ }
+ return true;
+ }
+
+ private void setSelectedProfile(String key) {
+ try {
+ UUID selectedUuid = UUID.fromString(key);
+ mProfileManager.setActiveProfile(selectedUuid);
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfilesPreference.java b/src/com/android/settings/profiles/ProfilesPreference.java
new file mode 100644
index 0000000..91f57ad
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfilesPreference.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.content.ActivityNotFoundException;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.PreferenceActivity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+
+public class ProfilesPreference extends CheckBoxPreference {
+ private static final String TAG = ProfilesPreference.class.getSimpleName();
+ private static final float DISABLED_ALPHA = 0.4f;
+ private final SettingsPreferenceFragment mFragment;
+ private final Bundle mSettingsBundle;
+
+ // constant value that can be used to check return code from sub activity.
+ private static final int PROFILE_DETAILS = 1;
+
+ private ImageView mProfilesSettingsButton;
+ private TextView mTitleText;
+ private TextView mSummaryText;
+ private View mProfilesPref;
+
+ private final OnClickListener mPrefOnclickListener = new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ if (!isEnabled() || isChecked()) {
+ return;
+ }
+ setChecked(true);
+ callChangeListener(getKey());
+ }
+ };
+
+ public ProfilesPreference(SettingsPreferenceFragment fragment, Bundle settingsBundle) {
+ super(fragment.getActivity(), null, R.style.ProfilesPreferenceStyle);
+ setLayoutResource(R.layout.preference_profiles);
+ setWidgetLayoutResource(R.layout.preference_profiles_widget);
+ mFragment = fragment;
+ mSettingsBundle = settingsBundle;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ mProfilesPref = view.findViewById(R.id.profiles_pref);
+ mProfilesPref.setOnClickListener(mPrefOnclickListener);
+ mProfilesSettingsButton = (ImageView)view.findViewById(R.id.profiles_settings);
+ mTitleText = (TextView)view.findViewById(android.R.id.title);
+ mSummaryText = (TextView)view.findViewById(android.R.id.summary);
+
+ if (mSettingsBundle != null) {
+ mProfilesSettingsButton.setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ try {
+ startProfileConfigActivity();
+ } catch (ActivityNotFoundException e) {
+ // If the settings activity does not exist, we can just
+ // do nothing...
+ }
+ }
+ });
+ }
+ if (mSettingsBundle == null) {
+ mProfilesSettingsButton.setVisibility(View.GONE);
+ } else {
+ updatePreferenceViews();
+ }
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ if (enabled) {
+ updatePreferenceViews();
+ } else {
+ disablePreferenceViews();
+ }
+ }
+
+ private void disablePreferenceViews() {
+ if (mProfilesSettingsButton != null) {
+ mProfilesSettingsButton.setEnabled(false);
+ mProfilesSettingsButton.setAlpha(DISABLED_ALPHA);
+ }
+ if (mProfilesPref != null) {
+ mProfilesPref.setEnabled(false);
+ mProfilesPref.setBackgroundColor(0);
+ }
+ }
+
+ private void updatePreferenceViews() {
+ final boolean checked = isChecked();
+ if (mProfilesSettingsButton != null) {
+ mProfilesSettingsButton.setEnabled(true);
+ mProfilesSettingsButton.setClickable(true);
+ mProfilesSettingsButton.setFocusable(true);
+ }
+ if (mTitleText != null) {
+ mTitleText.setEnabled(true);
+ }
+ if (mSummaryText != null) {
+ mSummaryText.setEnabled(checked);
+ }
+ if (mProfilesPref != null) {
+ mProfilesPref.setEnabled(true);
+ mProfilesPref.setLongClickable(checked);
+ final boolean enabled = isEnabled();
+ mProfilesPref.setOnClickListener(enabled ? mPrefOnclickListener : null);
+ if (!enabled) {
+ mProfilesPref.setBackgroundColor(0);
+ }
+ }
+ }
+
+ // utility method used to start sub activity
+ private void startProfileConfigActivity() {
+ SettingsActivity pa = (SettingsActivity) mFragment.getActivity();
+ pa.startPreferencePanel(ProfileConfig.class.getName(), mSettingsBundle,
+ R.string.profile_profile_manage, null, mFragment, PROFILE_DETAILS);
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ super.setChecked(checked);
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfilesSettings.java b/src/com/android/settings/profiles/ProfilesSettings.java
new file mode 100644
index 0000000..2576858
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfilesSettings.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.NotificationGroup;
+import android.app.Profile;
+import android.app.ProfileManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.provider.Settings;
+import android.support.v4.view.PagerTabStrip;
+import android.support.v4.view.ViewPager;
+import android.support.v13.app.FragmentStatePagerAdapter;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+
+import java.util.HashMap;
+
+public class ProfilesSettings extends SettingsPreferenceFragment {
+
+ private static final String TAG = "ProfilesSettings";
+ private static final String PROFILE_SERVICE = "profile";
+
+ private static final int MENU_RESET = Menu.FIRST;
+ private static final int MENU_ADD = Menu.FIRST + 1;
+
+ private final IntentFilter mFilter;
+ private final BroadcastReceiver mReceiver;
+
+ private ProfileManager mProfileManager;
+ private ProfileEnabler mProfileEnabler;
+
+ private Switch mActionBarSwitch;
+
+ private ViewPager mViewPager;
+ private TextView mEmptyText;
+ private ProfilesPagerAdapter mAdapter;
+ private boolean mEnabled;
+
+ ViewGroup mContainer;
+
+ static Bundle mSavedState;
+
+ public ProfilesSettings() {
+ mFilter = new IntentFilter();
+ mFilter.addAction(ProfileManager.PROFILES_STATE_CHANGED_ACTION);
+
+ mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ProfileManager.PROFILES_STATE_CHANGED_ACTION.equals(action)) {
+ updateProfilesEnabledState();
+ }
+ }
+ };
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mContainer = container;
+
+ View view = inflater.inflate(R.layout.profile_tabs, container, false);
+ mViewPager = (ViewPager) view.findViewById(R.id.pager);
+ mEmptyText = (TextView) view.findViewById(R.id.empty);
+
+ mAdapter = new ProfilesPagerAdapter(getFragmentManager());
+ mViewPager.setAdapter(mAdapter);
+
+ PagerTabStrip tabs = (PagerTabStrip) view.findViewById(R.id.tabs);
+ tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
+
+ mProfileManager = (ProfileManager) getActivity().getSystemService(PROFILE_SERVICE);
+
+ setHasOptionsMenu(true);
+
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ // We don't call super.onActivityCreated() here, since it assumes we already set up
+ // Preference (probably in onCreate()), while ProfilesSettings exceptionally set it up in
+ // this method.
+ // On/off switch
+ Activity activity = getActivity();
+ //Switch
+ mActionBarSwitch = new Switch(activity);
+
+ if (activity instanceof PreferenceActivity) {
+ PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
+ if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
+ final int padding = activity.getResources().getDimensionPixelSize(
+ R.dimen.action_bar_switch_padding);
+ mActionBarSwitch.setPaddingRelative(0, 0, padding, 0);
+ activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+ ActionBar.DISPLAY_SHOW_CUSTOM);
+ activity.getActionBar().setCustomView(mActionBarSwitch, new ActionBar.LayoutParams(
+ ActionBar.LayoutParams.WRAP_CONTENT,
+ ActionBar.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_VERTICAL | Gravity.END));
+ }
+ }
+
+ mProfileEnabler = new ProfileEnabler(activity, mActionBarSwitch);
+
+ // After confirming PreferenceScreen is available, we call super.
+ super.onActivityCreated(savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mProfileEnabler != null) {
+ mProfileEnabler.resume();
+ }
+ getActivity().registerReceiver(mReceiver, mFilter);
+
+ // check if we are enabled
+ updateProfilesEnabledState();
+
+ // If running on a phone, remove padding around tabs
+ if (!Utils.isTablet(getActivity())) {
+ mContainer.setPadding(0, 0, 0, 0);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mProfileEnabler != null) {
+ mProfileEnabler.pause();
+ }
+ getActivity().unregisterReceiver(mReceiver);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(0, MENU_RESET, 0, R.string.profile_reset_title)
+ .setIcon(R.drawable.ic_settings_backup) // use the backup icon
+ .setAlphabeticShortcut('r')
+ .setEnabled(mEnabled)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ menu.add(0, MENU_ADD, 0, R.string.profiles_add)
+ .setIcon(R.drawable.ic_menu_add)
+ .setAlphabeticShortcut('a')
+ .setEnabled(mEnabled)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+ MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ resetAll();
+ return true;
+
+ case MENU_ADD:
+ // determine dialog to launch
+ if (mViewPager.getCurrentItem() == 0) {
+ addProfile();
+ } else {
+ addAppGroup();
+ }
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ private void addProfile() {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View content = inflater.inflate(R.layout.profile_name_dialog, null);
+ final TextView prompt = (TextView) content.findViewById(R.id.prompt);
+ final EditText entry = (EditText) content.findViewById(R.id.name);
+
+ prompt.setText(R.string.profile_profile_name_prompt);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.menu_new_profile);
+ builder.setView(content);
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String name = entry.getText().toString();
+ if (!mProfileManager.profileExists(name)) {
+ Profile profile = new Profile(name);
+ mProfileManager.addProfile(profile);
+ mAdapter.refreshProfiles();
+ } else {
+ Toast.makeText(getActivity(),
+ R.string.duplicate_profile_name, Toast.LENGTH_LONG).show();
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private void resetAll() {
+ AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
+ alert.setTitle(R.string.profile_reset_title);
+ alert.setIconAttribute(android.R.attr.alertDialogIcon);
+ alert.setMessage(R.string.profile_reset_message);
+ alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ mProfileManager.resetAll();
+ mAdapter.refreshProfiles();
+ mAdapter.refreshAppGroups();
+ }
+ });
+ alert.setNegativeButton(R.string.cancel, null);
+ alert.show();
+ }
+
+ private void addAppGroup() {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View content = inflater.inflate(R.layout.profile_name_dialog, null);
+ final TextView prompt = (TextView) content.findViewById(R.id.prompt);
+ final EditText entry = (EditText) content.findViewById(R.id.name);
+
+ prompt.setText(R.string.profile_appgroup_name_prompt);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.profile_new_appgroup);
+ builder.setView(content);
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String name = entry.getText().toString();
+ if (!mProfileManager.notificationGroupExists(name)) {
+ NotificationGroup newGroup = new NotificationGroup(name);
+ mProfileManager.addNotificationGroup(newGroup);
+ mAdapter.refreshAppGroups();
+ } else {
+ Toast.makeText(getActivity(),
+ R.string.duplicate_appgroup_name, Toast.LENGTH_LONG).show();
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ private void updateProfilesEnabledState() {
+ Activity activity = getActivity();
+
+ mEnabled = Settings.System.getInt(activity.getContentResolver(),
+ Settings.System.SYSTEM_PROFILES_ENABLED, 1) == 1;
+ activity.invalidateOptionsMenu();
+
+ mViewPager.setVisibility(mEnabled ? View.VISIBLE : View.GONE);
+ mEmptyText.setVisibility(mEnabled ? View.GONE : View.VISIBLE);
+ }
+
+ class ProfilesPagerAdapter extends FragmentStatePagerAdapter {
+ Fragment[] frags = { new ProfilesList(), new AppGroupList() };
+ String[] titles = { getString(R.string.profile_profiles_manage),
+ getString(R.string.profile_appgroups_manage) };
+
+ ProfilesPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return frags[position];
+ }
+
+ @Override
+ public int getCount() {
+ return frags.length;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return titles[position];
+ }
+
+ public void refreshProfiles() {
+ ((ProfilesList) frags[0]).refreshList();
+ }
+
+ public void refreshAppGroups() {
+ ((AppGroupList) frags[1]).refreshList();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/ProfilesUtils.java b/src/com/android/settings/profiles/ProfilesUtils.java
new file mode 100644
index 0000000..4f59dd9
--- /dev/null
+++ b/src/com/android/settings/profiles/ProfilesUtils.java
@@ -0,0 +1,68 @@
+package com.android.settings.profiles;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.hardware.Camera;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.WifiDisplayStatus;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.net.ConnectivityManager;
+import android.nfc.NfcAdapter;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.PhoneConstants;
+
+public class ProfilesUtils {
+ public static boolean deviceSupportsUsbTether(Context ctx) {
+ ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return (cm.getTetherableUsbRegexs().length != 0);
+ }
+
+ public static boolean deviceSupportsWifiDisplay(Context ctx) {
+ DisplayManager dm = (DisplayManager) ctx.getSystemService(Context.DISPLAY_SERVICE);
+ return (dm.getWifiDisplayStatus().getFeatureState() != WifiDisplayStatus.FEATURE_STATE_UNAVAILABLE);
+ }
+
+ public static boolean deviceSupportsMobileData(Context ctx) {
+ ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ }
+
+ public static boolean deviceSupportsBluetooth() {
+ return (BluetoothAdapter.getDefaultAdapter() != null);
+ }
+
+ public static boolean systemProfilesEnabled(ContentResolver resolver) {
+ return (Settings.System.getInt(resolver, Settings.System.SYSTEM_PROFILES_ENABLED, 1) == 1);
+ }
+
+ public static boolean deviceSupportsNfc(Context ctx) {
+ return NfcAdapter.getDefaultAdapter(ctx) != null;
+ }
+
+ public static boolean deviceSupportsCamera() {
+ return Camera.getNumberOfCameras() > 0;
+ }
+
+ public static boolean deviceSupportsGps(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
+ }
+
+ public static boolean adbEnabled(ContentResolver resolver) {
+ return (Settings.Global.getInt(resolver, Settings.Global.ADB_ENABLED, 0)) == 1;
+ }
+
+ public static boolean deviceSupportsCompass(Context context) {
+ SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ return (sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null
+ && sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null);
+ }
+}
diff --git a/src/com/android/settings/profiles/StreamVolumePreference.java b/src/com/android/settings/profiles/StreamVolumePreference.java
new file mode 100644
index 0000000..6788aca
--- /dev/null
+++ b/src/com/android/settings/profiles/StreamVolumePreference.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.media.AudioManager;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+
+import com.android.settings.R;
+
+public class StreamVolumePreference extends Preference implements
+ CompoundButton.OnCheckedChangeListener, View.OnClickListener {
+
+ private boolean mProtectFromCheckedChange = false;
+
+ private CheckBox mCheckBox;
+
+ final static String TAG = "StreamVolumePreference";
+
+ private ProfileConfig.StreamItem mStreamItem;
+
+ private SeekBar mBar;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public StreamVolumePreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public StreamVolumePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * @param context
+ */
+ public StreamVolumePreference(Context context) {
+ super(context);
+ init();
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ View view = super.getView(convertView, parent);
+
+ View widget = view.findViewById(R.id.profile_checkbox);
+ if ((widget != null) && widget instanceof CheckBox) {
+ mCheckBox = (CheckBox) widget;
+ mCheckBox.setOnCheckedChangeListener(this);
+
+ mProtectFromCheckedChange = true;
+ mCheckBox.setChecked(isChecked());
+ mProtectFromCheckedChange = false;
+ }
+
+ View textLayout = view.findViewById(R.id.text_layout);
+ if ((textLayout != null) && textLayout instanceof LinearLayout) {
+ textLayout.setOnClickListener(this);
+ }
+
+ return view;
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.preference_streamvolume);
+ }
+
+ public boolean isChecked() {
+ return mStreamItem != null && mStreamItem.mSettings.isOverride();
+ }
+
+ public void setStreamItem(ProfileConfig.StreamItem streamItem) {
+ mStreamItem = streamItem;
+
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mStreamItem.mSettings.isOverride());
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mProtectFromCheckedChange) {
+ return;
+ }
+
+ mStreamItem.mSettings.setOverride(isChecked);
+
+ callChangeListener(isChecked);
+ }
+
+ protected Dialog createVolumeDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ final AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ builder.setTitle(mStreamItem.mLabel);
+ mBar = new SeekBar(getContext());
+ mBar.setPaddingRelative(32, 16, 32, 16); // TODO: confirm appropriate padding
+ mBar.setMax(am.getStreamMaxVolume(mStreamItem.mStreamId));
+ mBar.setProgress(mStreamItem.mSettings.getValue());
+ builder.setView(mBar);
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int value = mBar.getProgress();
+ mStreamItem.mSettings.setValue(value);
+ setSummary(getContext().getString(R.string.volume_override_summary) + " " + value + "/" + mBar.getMax());
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ return builder.create();
+ }
+
+ public ProfileConfig.StreamItem getStreamItem() {
+ return mStreamItem;
+ }
+
+ @Override
+ public void onClick(android.view.View v) {
+ if ((v != null) && (R.id.text_layout == v.getId())) {
+ createVolumeDialog().show();
+ }
+ }
+}
diff --git a/src/com/android/settings/profiles/TriggersFragment.java b/src/com/android/settings/profiles/TriggersFragment.java
new file mode 100644
index 0000000..5da8186
--- /dev/null
+++ b/src/com/android/settings/profiles/TriggersFragment.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Profile;
+import android.app.Profile.ProfileTrigger;
+import android.app.Profile.TriggerType;
+import android.app.ProfileManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.widget.ArrayAdapter;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Settings Preference to configure triggers to switch profiles base on Wi-Fi events
+ */
+public class TriggersFragment extends SettingsPreferenceFragment implements ActionBar.OnNavigationListener {
+ private Profile mProfile;
+ private Preference mSelectedTrigger;
+ private ProfileManager mProfileManager;
+ private WifiManager mWifiManager;
+ private BluetoothAdapter mBluetoothAdapter;
+
+ private int mTriggerFilter = 0;
+ private static final int WIFI_TRIGGER = 1;
+ private static final int BT_TRIGGER = 2;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mProfileManager = (ProfileManager) getSystemService(Context.PROFILE_SERVICE);
+ mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();;
+ addPreferencesFromResource(R.xml.wifi_settings);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ loadPreferences();
+ loadActionBar();
+ }
+
+ private void loadActionBar() {
+ final ActionBar actionBar = getActivity().getActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+ Resources res = getResources();
+
+ String[] navItems = res.getStringArray(R.array.profile_trigger_filters);
+ ArrayAdapter<String> navAdapter = new ArrayAdapter<String>(
+ actionBar.getThemedContext(), android.R.layout.simple_list_item_1, navItems);
+
+ // Set up the dropdown list navigation in the action bar.
+ actionBar.setListNavigationCallbacks(navAdapter, this);
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP
+ | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Bundle args = getArguments();
+ if (args != null) {
+ mProfile = args.getParcelable("profile");
+ }
+ }
+
+ private void initPreference(AbstractTriggerPreference pref, int state, Resources res, int icon) {
+ String summary = res.getStringArray(R.array.profile_trigger_wifi_options)[state];
+ pref.setSummary(summary);
+ pref.setTriggerState(state);
+ pref.setIcon(icon);
+ }
+
+ private void loadPreferences() {
+ final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ final Resources res = getResources();
+ final List<AbstractTriggerPreference> prefs = new ArrayList<AbstractTriggerPreference>();
+
+ getPreferenceScreen().removeAll();
+
+ if (mTriggerFilter == WIFI_TRIGGER || mTriggerFilter == 0) {
+ if (configs != null ) {
+ for (WifiConfiguration config : configs) {
+ WifiTriggerAPPreference accessPoint =
+ new WifiTriggerAPPreference(getActivity(), config);
+ int state = mProfile.getTrigger(Profile.TriggerType.WIFI, accessPoint.getSSID());
+ initPreference(accessPoint, state, res, R.drawable.ic_wifi_signal_4_dark);
+ prefs.add(accessPoint);
+ }
+ } else {
+ final List<ProfileTrigger> triggers = mProfile.getTriggersFromType(TriggerType.WIFI);
+ for (ProfileTrigger trigger : triggers) {
+ WifiTriggerAPPreference accessPoint =
+ new WifiTriggerAPPreference(getActivity(), trigger.getName());
+ initPreference(accessPoint, trigger.getState(), res, R.drawable.ic_wifi_signal_4_dark);
+ prefs.add(accessPoint);
+ }
+ }
+ }
+
+ Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+ if (mTriggerFilter == BT_TRIGGER || mTriggerFilter == 0) {
+ if (!pairedDevices.isEmpty()) {
+ for (BluetoothDevice device : pairedDevices) {
+ BluetoothTriggerPreference bt =
+ new BluetoothTriggerPreference(getActivity(), device);
+ int state = mProfile.getTrigger(Profile.TriggerType.BLUETOOTH, bt.getAddress());
+ initPreference(bt, state, res, R.drawable.ic_settings_bluetooth2);
+ prefs.add(bt);
+ }
+ } else {
+ final List<ProfileTrigger> triggers = mProfile.getTriggersFromType(TriggerType.BLUETOOTH);
+ for (ProfileTrigger trigger : triggers) {
+ BluetoothTriggerPreference bt = new BluetoothTriggerPreference(getActivity(),
+ trigger.getName(), trigger.getId());
+ initPreference(bt, trigger.getState(), res, R.drawable.ic_settings_bluetooth2);
+ prefs.add(bt);
+ }
+ }
+ }
+
+ Collections.sort(prefs, new Comparator<AbstractTriggerPreference>() {
+ @Override
+ public int compare(AbstractTriggerPreference o1, AbstractTriggerPreference o2) {
+ if (o1.getTriggerState() == o2.getTriggerState()) {
+ return o1.compareTo(o2);
+ }
+ return o1.getTriggerState() < o2.getTriggerState() ? -1 : 1;
+ }
+ });
+ for (Preference pref: prefs) {
+ getPreferenceScreen().addPreference(pref);
+ }
+
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
+ mSelectedTrigger = preference;
+ if (preference instanceof WifiTriggerAPPreference) {
+ showDialog(WIFI_TRIGGER);
+ return true;
+ } else if (preference instanceof BluetoothTriggerPreference) {
+ showDialog(BT_TRIGGER);
+ return true;
+ }
+ return super.onPreferenceTreeClick(screen, preference);
+ }
+
+ @Override
+ public Dialog onCreateDialog(final int dialogId) {
+ final String id;
+ final String triggerName = mSelectedTrigger.getTitle().toString();
+ final int triggerType;
+
+ switch (dialogId) {
+ case WIFI_TRIGGER:
+ WifiTriggerAPPreference pref = (WifiTriggerAPPreference) mSelectedTrigger;
+ id = pref.getSSID();
+ triggerType = Profile.TriggerType.WIFI;
+ break;
+ case BT_TRIGGER:
+ BluetoothTriggerPreference btpref = (BluetoothTriggerPreference) mSelectedTrigger;
+ id = btpref.getAddress();
+ triggerType = Profile.TriggerType.BLUETOOTH;
+ break;
+ default:
+ return super.onCreateDialog(dialogId);
+ }
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.profile_trigger_configure)
+ .setSingleChoiceItems(R.array.profile_trigger_wifi_options,
+ mProfile.getTrigger(triggerType, id),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mProfile.setTrigger(triggerType, id, which, triggerName);
+ mProfileManager.updateProfile(mProfile);
+ loadPreferences();
+ dialog.dismiss();
+ }
+ })
+ .create();
+ }
+
+ @Override
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+ mTriggerFilter = itemPosition;
+ loadPreferences();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/profiles/WifiTriggerAPPreference.java b/src/com/android/settings/profiles/WifiTriggerAPPreference.java
new file mode 100644
index 0000000..239509a
--- /dev/null
+++ b/src/com/android/settings/profiles/WifiTriggerAPPreference.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.profiles;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+
+public class WifiTriggerAPPreference extends AbstractTriggerPreference {
+
+ private String mSSID;
+ private WifiConfiguration mConfig;
+
+ WifiTriggerAPPreference(Context context, WifiConfiguration config) {
+ super(context);
+ loadConfig(config);
+ setTitle(mSSID);
+ }
+
+ WifiTriggerAPPreference(Context context, String ssid) {
+ super(context);
+ mSSID = ssid;
+ setTitle(mSSID);
+ }
+
+ private void loadConfig(WifiConfiguration config) {
+ mSSID = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+ mConfig = config;
+ }
+
+ public String getSSID() {
+ return mSSID;
+ }
+
+ public static String removeDoubleQuotes(String string) {
+ final int length = string.length();
+ if (length >= 2) {
+ if (string.startsWith("\"") && string.endsWith("\"")) {
+ return string.substring(1, length - 1);
+ }
+ }
+ return string;
+ }
+}