Merge the 2021-03-05 SPL branch from AOSP-Partner
* security-aosp-pi-release:
RESTRICT AUTOMERGE Update String
RESTRICT AUTOMERGE Fix phishing attacks over Bluetooth due to unclear warning message
Change-Id: Ia90455c725f93e7328b81ba84bc804e75a074af2
diff --git a/Android.mk b/Android.mk
index e37e9fb..0be3258 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,7 +36,8 @@
LOCAL_JAVA_LIBRARIES := \
bouncycastle \
telephony-common \
- ims-common
+ ims-common \
+ com.fairphone.common
LOCAL_STATIC_JAVA_LIBRARIES := \
android-arch-lifecycle-runtime \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4456aa0..3f09fc5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -109,6 +109,8 @@
android:appComponentFactory="android.support.v4.app.CoreComponentFactory">
<uses-library android:name="org.apache.http.legacy" />
+
+ <uses-library android:name="com.fairphone.common" />
<!-- Settings -->
<activity android:name="Settings"
@@ -1256,6 +1258,21 @@
</intent-filter>
</activity>
+ <activity android:name="Settings$AppOpsSummaryActivity"
+ android:label="@string/privacy_guard_manager_title"
+ android:taskAffinity=""
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.settings.APP_OPS_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE_LAUNCH" />
+ <category android:name="com.android.settings.SHORTCUT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.applications.appops.AppOpsSummary" />
+ </activity>
+
<activity android:name="Settings$BackgroundCheckSummaryActivity"
android:label="@string/background_check_title"
android:enabled="false">
@@ -1267,6 +1284,30 @@
android:value="com.android.settings.applications.appops.BackgroundCheckSummary" />
</activity>
+ <!-- Still need a top-level activity for showing app ops details. Aliasing
+ trick is so the code that is now a fragment can still be called
+ AppOpsDetails. -->
+ <activity android:name=".applications.appops.AppOpsDetailsTop"
+ android:label="@string/privacy_guard_manager_title"
+ android:exported="true"
+ android:taskAffinity=""
+ android:excludeFromRecents="true"
+ android:parentActivityName="Settings$AppOpsSummaryActivity">
+ </activity>
+
+ <!-- Keep compatibility with old shortcuts. -->
+ <activity-alias android:name=".applications.appops.AppOpsDetails"
+ android:label="@string/privacy_guard_manager_title"
+ android:exported="true"
+ android:excludeFromRecents="true"
+ android:targetActivity=".applications.appops.AppOpsDetailsTop">
+ <intent-filter>
+ <action android:name="android.settings.APP_OPS_DETAILS_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </activity-alias>
+
<activity
android:name="Settings$LocationSettingsActivity"
android:label="@string/location_settings_title"
@@ -2878,6 +2919,7 @@
<activity android:name=".sim.SimDialogActivity"
android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
android:label="@string/sim_settings_title"
+ android:process="com.android.phone"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/proguard.flags b/proguard.flags
index 43a038b..74cb791 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -29,6 +29,8 @@
*** get*();
}
+-keep class com.android.settings.lineageos.*Settings
+
# Keep classes that may be inflated from XML.
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
diff --git a/res/drawable/ic_perm_alarm.xml b/res/drawable/ic_perm_alarm.xml
new file mode 100644
index 0000000..3bb90b8
--- /dev/null
+++ b/res/drawable/ic_perm_alarm.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24.0dp"
+ android:width="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,20A7,7 0 0,1 5,13A7,7 0 0,1 12,6A7,7 0 0,1 19,13A7,7 0 0,1 12,20M12,4A9,9 0 0,0 3,13A9,9 0 0,0 12,22A9,9 0 0,0 21,13A9,9 0 0,0 12,4M12.5,8H11V14L15.75,16.85L16.5,15.62L12.5,13.25V8M7.88,3.39L6.6,1.86L2,5.71L3.29,7.24L7.88,3.39M22,5.72L17.4,1.86L16.11,3.39L20.71,7.25L22,5.72Z" />
+</vector>
diff --git a/res/drawable/ic_perm_audio.xml b/res/drawable/ic_perm_audio.xml
new file mode 100644
index 0000000..3b9c4d2
--- /dev/null
+++ b/res/drawable/ic_perm_audio.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 12 3 v 9.28 c -0.47 -0.17 -0.97 -0.28 -1.5 -0.28 C 8.01 12 6 14.01 6 16.5 S 8.01 21 10.5 21 c 2.31 0 4.2 -1.75 4.45 -4 H 15 V 6 h 4 V 3 h -7 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_background.xml b/res/drawable/ic_perm_background.xml
new file mode 100644
index 0000000..8d4ab89
--- /dev/null
+++ b/res/drawable/ic_perm_background.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 9 7 H 7 v 2 h 2 V 7 Z m 0 4 H 7 v 2 h 2 v -2 Z m 0 -8 c -1.11 0 -2 0.9 -2 2 h 2 V 3 Z m 4 12 h -2 v 2 h 2 v -2 Z m 6 -12 v 2 h 2 c 0 -1.1 -0.9 -2 -2 -2 Z m -6 0 h -2 v 2 h 2 V 3 Z M 9 17 v -2 H 7 c 0 1.1 0.89 2 2 2 Z m 10 -4 h 2 v -2 h -2 v 2 Z m 0 -4 h 2 V 7 h -2 v 2 Z m 0 8 c 1.1 0 2 -0.9 2 -2 h -2 v 2 Z M 5 7 H 3 v 12 c 0 1.1 0.89 2 2 2 h 12 v -2 H 5 V 7 Z m 10 -2 h 2 V 3 h -2 v 2 Z m 0 12 h 2 v -2 h -2 v 2 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_bluetooth.xml b/res/drawable/ic_perm_bluetooth.xml
new file mode 100644
index 0000000..f68ba29
--- /dev/null
+++ b/res/drawable/ic_perm_bluetooth.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M14.88,16.29L13,18.17V14.41M13,5.83L14.88,7.71L13,9.58M17.71,7.71L12,2H11V9.58L6.41,5L5,6.41L10.59,12L5,17.58L6.41,19L11,14.41V22H12L17.71,16.29L13.41,12L17.71,7.71Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_boot.xml b/res/drawable/ic_perm_boot.xml
new file mode 100644
index 0000000..197877a
--- /dev/null
+++ b/res/drawable/ic_perm_boot.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,1C8.14,1 5,4.14 5,8A7,7 0 0,0 12,15C15.86,15 19,11.87 19,8C19,4.14 15.86,1 12,1M12,3.15C14.67,3.15 16.85,5.32 16.85,8C16.85,10.68 14.67,12.85 12,12.85A4.85,4.85 0 0,1 7.15,8A4.85,4.85 0 0,1 12,3.15M11,5V8.69L14.19,10.53L14.94,9.23L12.5,7.82V5M4,16V24H6V21H18V24L22,20L18,16V19H6V16"/>
+</vector>
diff --git a/res/drawable/ic_perm_clipboard.xml b/res/drawable/ic_perm_clipboard.xml
new file mode 100644
index 0000000..d9a3c4b
--- /dev/null
+++ b/res/drawable/ic_perm_clipboard.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,9H7V7H17M17,13H7V11H17M14,17H7V15H14M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_data.xml b/res/drawable/ic_perm_data.xml
new file mode 100644
index 0000000..d258b49c
--- /dev/null
+++ b/res/drawable/ic_perm_data.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,2.05V5.08C16.39,5.57 19,8.47 19,12C19,12.9 18.82,13.75 18.5,14.54L21.12,16.07C21.68,14.83 22,13.45 22,12C22,6.82 18.05,2.55 13,2.05M12,19A7,7 0 0,1 5,12C5,8.47 7.61,5.57 11,5.08V2.05C5.94,2.55 2,6.81 2,12A10,10 0 0,0 12,22C15.3,22 18.23,20.39 20.05,17.91L17.45,16.38C16.17,18 14.21,19 12,19Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_drawontop.xml b/res/drawable/ic_perm_drawontop.xml
new file mode 100644
index 0000000..170de0c
--- /dev/null
+++ b/res/drawable/ic_perm_drawontop.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 3 13 h 2 v -2 H 3 v 2 Z m 0 4 h 2 v -2 H 3 v 2 Z m 2 4 v -2 H 3 c 0 1.1 0.89 2 2 2 Z M 3 9 h 2 V 7 H 3 v 2 Z m 12 12 h 2 v -2 h -2 v 2 Z m 4 -18 H 9 c -1.11 0 -2 0.9 -2 2 v 10 c 0 1.1 0.89 2 2 2 h 10 c 1.1 0 2 -0.9 2 -2 V 5 c 0 -1.1 -0.9 -2 -2 -2 Z m 0 12 H 9 V 5 h 10 v 10 Z m -8 6 h 2 v -2 h -2 v 2 Z m -4 0 h 2 v -2 H 7 v 2 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_location.xml b/res/drawable/ic_perm_location.xml
new file mode 100644
index 0000000..3cba684
--- /dev/null
+++ b/res/drawable/ic_perm_location.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 12 2 C 8.13 2 5 5.13 5 9 c 0 5.25 7 13 7 13 s 7 -7.75 7 -13 c 0 -3.87 -3.13 -7 -7 -7 Z m 0 9.5 c -1.38 0 -2.5 -1.12 -2.5 -2.5 s 1.12 -2.5 2.5 -2.5 s 2.5 1.12 2.5 2.5 s -1.12 2.5 -2.5 2.5 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_microphone.xml b/res/drawable/ic_perm_microphone.xml
new file mode 100644
index 0000000..d8063ab
--- /dev/null
+++ b/res/drawable/ic_perm_microphone.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_nfc.xml b/res/drawable/ic_perm_nfc.xml
new file mode 100644
index 0000000..bbc1732
--- /dev/null
+++ b/res/drawable/ic_perm_nfc.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18,6H13A2,2 0 0,0 11,8V10.28C10.41,10.62 10,11.26 10,12A2,2 0 0,0 12,14C13.11,14 14,13.1 14,12C14,11.26 13.6,10.62 13,10.28V8H16V16H8V8H10V6H8L6,6V18H18M20,20H4V4H20M20,2H4A2,2 0 0,0 2,4V20A2,2 0 0,0 4,22H20C21.11,22 22,21.1 22,20V4C22,2.89 21.11,2 20,2Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_nosleep.xml b/res/drawable/ic_perm_nosleep.xml
new file mode 100644
index 0000000..1483f1f
--- /dev/null
+++ b/res/drawable/ic_perm_nosleep.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M2,5.27L3.28,4L20,20.72L18.73,22L12.73,16H9V14L9.79,13.06L2,5.27M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M9.82,8H15V10L13.54,11.72L9.82,8M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_notifications.xml b/res/drawable/ic_perm_notifications.xml
new file mode 100644
index 0000000..c6f27cd
--- /dev/null
+++ b/res/drawable/ic_perm_notifications.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.0,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0c0.0,1.0 0.89,2.0 2.0,2.0zm6.0,-6.0l0.0,-5.0c0.0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4.0c0.0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.0,0.67 -1.5,1.5l0.0,0.68C7.63,5.36 6.0,7.92 6.0,11.0l0.0,5.0l-2.0,2.0l0.0,1.0l16.0,0.0l0.0,-1.0l-2.0,-2.0z"/>
+</vector>
diff --git a/res/drawable/ic_perm_settings.xml b/res/drawable/ic_perm_settings.xml
new file mode 100644
index 0000000..7562a76
--- /dev/null
+++ b/res/drawable/ic_perm_settings.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 19.43 12.98 c 0.04 -0.32 0.07 -0.64 0.07 -0.98 s -0.03 -0.66 -0.07 -0.98 l 2.11 -1.65 c 0.19 -0.15 0.24 -0.42 0.12 -0.64 l -2 -3.46 c -0.12 -0.22 -0.39 -0.3 -0.61 -0.22 l -2.49 1 c -0.52 -0.4 -1.08 -0.73 -1.69 -0.98 l -0.38 -2.65 C 14.46 2.18 14.25 2 14 2 h -4 c -0.25 0 -0.46 0.18 -0.49 0.42 l -0.38 2.65 c -0.61 0.25 -1.17 0.59 -1.69 0.98 l -2.49 -1 c -0.23 -0.09 -0.49 0 -0.61 0.22 l -2 3.46 c -0.13 0.22 -0.07 0.49 0.12 0.64 l 2.11 1.65 c -0.04 0.32 -0.07 0.65 -0.07 0.98 s 0.03 0.66 0.07 0.98 l -2.11 1.65 c -0.19 0.15 -0.24 0.42 -0.12 0.64 l 2 3.46 c 0.12 0.22 0.39 0.3 0.61 0.22 l 2.49 -1 c 0.52 0.4 1.08 0.73 1.69 0.98 l 0.38 2.65 c 0.03 0.24 0.24 0.42 0.49 0.42 h 4 c 0.25 0 0.46 -0.18 0.49 -0.42 l 0.38 -2.65 c 0.61 -0.25 1.17 -0.59 1.69 -0.98 l 2.49 1 c 0.23 0.09 0.49 0 0.61 -0.22 l 2 -3.46 c 0.12 -0.22 0.07 -0.49 -0.12 -0.64 l -2.11 -1.65 Z M 12 15.5 c -1.93 0 -3.5 -1.57 -3.5 -3.5 s 1.57 -3.5 3.5 -3.5 s 3.5 1.57 3.5 3.5 s -1.57 3.5 -3.5 3.5 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_sms.xml b/res/drawable/ic_perm_sms.xml
new file mode 100644
index 0000000..25b6393
--- /dev/null
+++ b/res/drawable/ic_perm_sms.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M 20 2 H 4 c -1.1 0 -1.99 0.9 -1.99 2 L 2 22 l 4 -4 h 14 c 1.1 0 2 -0.9 2 -2 V 4 c 0 -1.1 -0.9 -2 -2 -2 Z M 9 11 H 7 V 9 h 2 v 2 Z m 4 0 h -2 V 9 h 2 v 2 Z m 4 0 h -2 V 9 h 2 v 2 Z"/>
+</vector>
diff --git a/res/drawable/ic_perm_su.xml b/res/drawable/ic_perm_su.xml
new file mode 100644
index 0000000..0ae4ef2
--- /dev/null
+++ b/res/drawable/ic_perm_su.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.49,15.934h-2.373L9.24,21H6.966l0.89-5.066H5.051v-2.089h3.163l0.63-3.584H5.977V8.148h3.238 l0.902-5.141h2.261l-0.902,5.141h2.373l0.914-5.141h2.261l-0.902,5.141h2.719v2.113h-3.089l-0.63,3.584h2.78v2.089h-3.139L13.874,21 H11.6L12.49,15.934Z M10.488,13.845h2.36l0.63-3.584h-2.373L10.488,13.845z"/>
+</vector>
diff --git a/res/drawable/ic_perm_turnscreenon.xml b/res/drawable/ic_perm_turnscreenon.xml
new file mode 100644
index 0000000..e68ed6c
--- /dev/null
+++ b/res/drawable/ic_perm_turnscreenon.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z"/>
+</vector>
diff --git a/res/drawable/ic_perm_vibrate.xml b/res/drawable/ic_perm_vibrate.xml
new file mode 100644
index 0000000..15dade2
--- /dev/null
+++ b/res/drawable/ic_perm_vibrate.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0 15h2V9H0v6zm3 2h2V7H3v10zm19-8v6h2V9h-2zm-3 8h2V7h-2v10zM16.5 3h-9C6.67 3 6 3.67 6 4.5v15c0 .83.67 1.5 1.5 1.5h9c.83 0 1.5-.67 1.5-1.5v-15c0-.83-.67-1.5-1.5-1.5zM16 19H8V5h8v14z"/>
+</vector>
diff --git a/res/drawable/ic_perm_vpn.xml b/res/drawable/ic_perm_vpn.xml
new file mode 100644
index 0000000..0050c22
--- /dev/null
+++ b/res/drawable/ic_perm_vpn.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.65,10C11.7,7.31,8.9,5.5,5.78,6.12C3.49,6.58,1.62,8.41,1.14,10.7C0.32,14.57,3.26,18,7,18c2.61,0,4.83-1.67,5.65-4H16
+v2c0,1.1,0.9,2,2,2h0c1.1,0,2-0.9,2-2v-2h1c1.1,0,2-0.9,2-2v0c0-1.1-0.9-2-2-2H12.65z M7,14c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2 S8.1,14,7,14z"/>
+</vector>
diff --git a/res/drawable/ic_perm_wifi.xml b/res/drawable/ic_perm_wifi.xml
new file mode 100644
index 0000000..db5b477
--- /dev/null
+++ b/res/drawable/ic_perm_wifi.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="#FF000000">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M1 9l2 2c4.97-4.97 13.03-4.97 18 0l2-2C16.93 2.93 7.08 2.93 1 9zm8 8l3 3 3-3c-1.65-1.66-4.34-1.66-6 0zm-4-4l2 2c2.76-2.76 7.24-2.76 10 0l2-2C15.14 9.14 8.87 9.14 5 13z"/>
+</vector>
diff --git a/res/drawable/ic_settings_maintenance.xml b/res/drawable/ic_settings_maintenance.xml
new file mode 100644
index 0000000..6077079
--- /dev/null
+++ b/res/drawable/ic_settings_maintenance.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2020 Fairphone B.V.
+
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.09 2.91C10.08 0.9 7.07 0.49 4.65 1.67L8.28 5.3c0.39 0.39 0.39 1.02 0 1.41L6.69 8.3c-0.39 0.4 -1.02 0.4 -1.41 0L1.65 4.67C0.48 7.1 0.89 10.09 2.9 12.1c1.86 1.86 4.58 2.35 6.89 1.48l7.96 7.96c1.03 1.03 2.69 1.03 3.71 0 1.03 -1.03 1.03 -2.69 0 -3.71L13.54 9.9c0.92 -2.34 0.44 -5.1 -1.45 -6.99z"/>
+</vector>
diff --git a/res/layout/app_ops_summary.xml b/res/layout/app_ops_summary.xml
new file mode 100644
index 0000000..2073a00
--- /dev/null
+++ b/res/layout/app_ops_summary.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<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:paddingLeft="@dimen/pager_tabs_padding"
+ android:paddingRight="@dimen/pager_tabs_padding">
+ </android.support.v4.view.PagerTabStrip>
+ </android.support.v4.view.ViewPager>
+
+</LinearLayout>
diff --git a/res/layout/crypt_keeper_settings.xml b/res/layout/crypt_keeper_settings.xml
index 6b33e00..ad82b8c 100644
--- a/res/layout/crypt_keeper_settings.xml
+++ b/res/layout/crypt_keeper_settings.xml
@@ -30,13 +30,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
- <TextView
+ <!-- Encryption is disabled in this version of Fairphone OS. -->
+ <!-- <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dip"
android:layout_marginBottom="16dip"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/crypt_keeper_desc" />
+ android:text="@string/crypt_keeper_desc" /> -->
<TextView
android:id="@+id/warning_low_charge"
android:layout_width="match_parent"
@@ -55,6 +56,14 @@
android:textStyle="bold"
android:text="@string/crypt_keeper_unplugged_text"
android:visibility="gone" />
+ <TextView
+ android:id="@+id/message_unsupported"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@string/crypt_keeper_unsupported_text" />
</LinearLayout>
</ScrollView>
<Button
diff --git a/res/layout/dialog_hardware_info.xml b/res/layout/dialog_hardware_info.xml
index 7ea4783..fb0b15d 100644
--- a/res/layout/dialog_hardware_info.xml
+++ b/res/layout/dialog_hardware_info.xml
@@ -61,5 +61,65 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+ <TextView
+ style="@style/device_info_dialog_label"
+ android:id="@+id/assembly_number_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/assembly_number" />
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/assembly_number_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/device_info_dialog_label"
+ android:id="@+id/processor_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/processor_info" />
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/processor_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/device_info_dialog_label"
+ android:id="@+id/receiver_module_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/receiver_module_info" />
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/receiver_module_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/device_info_dialog_label"
+ android:id="@+id/camera_module_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/camera_module_info" />
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/camera_module_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ style="@style/device_info_dialog_label"
+ android:id="@+id/battery_module_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/battery_module_info" />
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/battery_module_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
</LinearLayout>
</ScrollView>
\ No newline at end of file
diff --git a/res/layout/preference_appops.xml b/res/layout/preference_appops.xml
new file mode 100644
index 0000000..db3c867
--- /dev/null
+++ b/res/layout/preference_appops.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2017 The LineageOS 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.
+-->
+
+<!-- Based off packages/apps/Settings/res/layout/preference_material_settings.xml
+ but with different paddings -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="56dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <com.android.internal.widget.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="48dp"
+ android:maxHeight="48dp" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <TextView android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:ellipsize="marquee" />
+
+ <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/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="16dp"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/res/menu/appops_manager.xml b/res/menu/appops_manager.xml
new file mode 100644
index 0000000..f89b738
--- /dev/null
+++ b/res/menu/appops_manager.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/show_user_apps"
+ android:title="@string/app_ops_show_user_apps"
+ android:checkable="true" />
+ <item android:id="@+id/show_system_apps"
+ android:title="@string/app_ops_show_system_apps"
+ android:checkable="true" />
+ <item android:id="@+id/reset_counters"
+ android:title="@string/app_ops_reset_counters" />
+</menu>
diff --git a/res/values-de/fairphone_strings.xml b/res/values-de/fairphone_strings.xml
new file mode 100644
index 0000000..e89e5a0
--- /dev/null
+++ b/res/values-de/fairphone_strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources>
+ <string name="crypt_keeper_unsupported_text">
+ Verschlüsselung ist momentan auf Android 9 auf dem FP2 nicht unterstützt. Um
+ dein Telefon zu verschlüsseln, installiere bitte Android 7, verschlüssele
+ dort und installiere dann das Upgrade auf Android 9.
+ </string>
+ <string name="maintenance_preference_title">"Wartung"</string>
+ <string name="proximity_sensor_title">"Näherungssensor"</string>
+ <string name="hiccup_summary">"Stabilitätsberichte"</string>
+ <string name="fairphone_setting_title">"Erweiterte Hardware-Funktionen"</string>
+ <string name="fairphone_settings_summary">"OpenGL ES 3.0 und hardware-beschleunigte Videowiedergabe aktivieren"</string>
+ <string name="assembly_number">"Fertigungsnummer"</string>
+ <string name="processor_info">"Prozessor"</string>
+ <string name="receiver_module_info">"Top-Modul Info"</string>
+ <string name="receiver_module_ov2685">"Front-Kamera 2MP – OmniVision OV2685"</string>
+ <string name="receiver_module_ov5670">"Front-Kamera 5MP – OmniVision OV5670"</string>
+ <string name="camera_module_info">"Camera-Modul Info"</string>
+ <string name="camera_module_ov8865">"Hauptkamera 8MP – OmniVision OV8865"</string>
+ <string name="camera_module_ov12870">"Hauptkamera 12MP – OmniVision OV12870"</string>
+ <string name="battery_module_info">"Informationen zum Akku"</string>
+</resources>
diff --git a/res/values-es/fairphone_strings.xml b/res/values-es/fairphone_strings.xml
new file mode 100644
index 0000000..dc9da6c
--- /dev/null
+++ b/res/values-es/fairphone_strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources>
+ <!-- <string name="crypt_keeper_unsupported_text">TODO</string> -->
+ <string name="maintenance_preference_title">"Mantenimiento"</string>
+ <string name="proximity_sensor_title">"Sensor de proximidad"</string>
+ <string name="hiccup_summary">"Informe de estabilidad"</string>
+ <!-- <string name="fairphone_setting_title">TODO</string> -->
+ <!-- <string name="fairphone_settings_summary">TODO</string> -->
+ <string name="assembly_number">"Número de ensamblaje"</string>
+ <string name="processor_info">"Procesador"</string>
+ <string name="receiver_module_info">"Información del módulo superior"</string>
+ <string name="receiver_module_ov2685">"Cámara frontal 2MP – OmniVision OV2685"</string>
+ <string name="receiver_module_ov5670">"Cámara frontal 5MP – OmniVision OV5670"</string>
+ <string name="camera_module_info">"Información del módulo de cámara"</string>
+ <string name="camera_module_ov8865">"Cámara principal – 8MP OmniVision OV8865"</string>
+ <string name="camera_module_ov12870">"Cámara principal – 12MP OmniVision OV12870"</string>
+ <string name="battery_module_info">"Información sobre la batería"</string>
+</resources>
diff --git a/res/values-fr/fairphone_strings.xml b/res/values-fr/fairphone_strings.xml
new file mode 100644
index 0000000..79ab54c
--- /dev/null
+++ b/res/values-fr/fairphone_strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources>
+ <string name="crypt_keeper_unsupported_text">
+ "Le cryptage du téléphone n'est actuellement pas pris en charge sur Android
+ 9 sur le FP2. Pour l'instant, pour crypter le téléphone, veuillez installer
+ Android 7, crypter et passer à nouveau à Android 9."
+ </string>
+ <string name="maintenance_preference_title">"Maintenance"</string>
+ <string name="proximity_sensor_title">"Capteur de proximité"</string>
+ <string name="hiccup_summary">"Rapport de stabilité"</string>
+ <string name="fairphone_setting_title">"Fonctionnalités matérielles améliorées"</string>
+ <string name="fairphone_settings_summary">"Activer OpenGL ES 3.0 et l'accélération matérielle pour la lecture vidéo"</string>
+ <string name="assembly_number">"Numéro d'assemblage"</string>
+ <string name="processor_info">"Processeur"</string>
+ <string name="receiver_module_info">"Informations sur le module supérieur"</string>
+ <string name="receiver_module_ov2685">"Caméra frontale 2MP – OmniVision OV2685"</string>
+ <string name="receiver_module_ov5670">"Caméra frontale 5MP – OmniVision OV5670"</string>
+ <string name="camera_module_info">"Informations sur le module caméra"</string>
+ <string name="camera_module_ov8865">"Caméra principale 8MP – OmniVision OV8865"</string>
+ <string name="camera_module_ov12870">"Caméra principale 12MP – OmniVision OV12870"</string>
+ <string name="battery_module_info">"Informations sur la batterie"</string>
+</resources>
diff --git a/res/values-it/fairphone_strings.xml b/res/values-it/fairphone_strings.xml
new file mode 100644
index 0000000..3f5cd67
--- /dev/null
+++ b/res/values-it/fairphone_strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources>
+ <!-- <string name="crypt_keeper_unsupported_text">TODO</string> -->
+ <!-- <string name="fairphone_setting_title">TODO</string> -->
+ <!-- <string name="fairphone_settings_summary">TODO</string> -->
+ <string name="assembly_number">"Numero di assemblaggio"</string>
+ <string name="processor_info">"Processore"</string>
+ <string name="receiver_module_info">"Informazioni sul modulo superiore"</string>
+ <string name="receiver_module_ov2685">"Fotocamera frontale 2MP – OmniVision OV2685"</string>
+ <string name="receiver_module_ov5670">"Fotocamera frontale 5MP – OmniVision OV5670"</string>
+ <string name="camera_module_info">"Informazioni sul modulo fotocamera"</string>
+ <string name="camera_module_ov8865">"Fotocamera principale 8MP – OmniVision OV8865"</string>
+ <string name="camera_module_ov12870">"Fotocamera principale 12MP – OmniVision OV12870"</string>
+ <string name="battery_module_info">"Informazioni sulla batteria"</string>
+</resources>
diff --git a/res/values-nl/fairphone_strings.xml b/res/values-nl/fairphone_strings.xml
new file mode 100644
index 0000000..4b0739b
--- /dev/null
+++ b/res/values-nl/fairphone_strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources>
+ <!-- <string name="crypt_keeper_unsupported_text">TODO</string> -->
+ <string name="maintenance_preference_title">"Onderhoud"</string>
+ <string name="proximity_sensor_title">"Afstandssensor"</string>
+ <string name="hiccup_summary">"Stabiliteitsrapportage"</string>
+ <!-- <string name="fairphone_setting_title">TODO</string> -->
+ <!-- <string name="fairphone_settings_summary">TODO</string> -->
+ <string name="assembly_number">"Assemblagenummer"</string>
+ <string name="processor_info">"Processor"</string>
+ <string name="receiver_module_info">"Bovenste module info"</string>
+ <string name="receiver_module_ov2685">"Camera voorzijde 2MP – OmniVision OV2685"</string>
+ <string name="receiver_module_ov5670">"Camera voorzijde 5MP – OmniVision OV5670"</string>
+ <string name="camera_module_info">"Cameramodule info"</string>
+ <string name="camera_module_ov8865">"Primaire camera 8MP – OmniVision OV8865"</string>
+ <string name="camera_module_ov12870">"Primaire camera 12MP – OmniVision OV12870"</string>
+ <string name="battery_module_info">"Batterij info"</string>
+</resources>
diff --git a/res/values/cm_plurals.xml b/res/values/cm_plurals.xml
new file mode 100644
index 0000000..af6e6dd
--- /dev/null
+++ b/res/values/cm_plurals.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013-2014 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <plurals name="app_ops_count">
+ <item quantity="one">once</item>
+ <item quantity="other">%d times</item>
+ </plurals>
+</resources>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
new file mode 100644
index 0000000..5620cc7
--- /dev/null
+++ b/res/values/cm_strings.xml
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2016 The CyanogenMod Project
+ Copyright (C) 2017 The LineageOS 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- App ops permissions -->
+ <string name="app_ops_permissions_allowed">Allowed</string>
+ <string name="app_ops_permissions_ignored">Ignored</string>
+ <string name="app_ops_permissions_always_ask">Always ask</string>
+
+ <!-- App ops detail -->
+ <string name="app_ops_entry_summary"><xliff:g id="op">%1$s</xliff:g> (used <xliff:g id="count">%2$s</xliff:g>)</string>
+ <string name="app_ops_allowed_count">Allowed <xliff:g id="count" example="2 times">%s</xliff:g></string>
+ <string name="app_ops_ignored_count">Denied <xliff:g id="count" example="2 times">%s</xliff:g></string>
+ <string name="app_ops_both_count">Allowed <xliff:g id="count">%1$s</xliff:g>, denied <xliff:g id="count">%2$s</xliff:g></string>
+ <string name="app_ops_no_blockable_permissions">No permissions available to block</string>
+
+ <!-- App ops menu options -->
+ <string name="app_ops_show_user_apps">Show user apps</string>
+ <string name="app_ops_show_system_apps">Show built-in apps</string>
+ <string name="app_ops_reset_counters">Reset allow/deny counters</string>
+ <string name="app_ops_reset_confirm_title">Confirm counters reset</string>
+ <string name="app_ops_reset_confirm_mesg">Are you sure you wish to reset counters?</string>
+
+ <!-- Memory -->
+ <string name="memory_startup_apps_title">Apps started on boot</string>
+
+ <!-- Names of categories of app ops tabs - extension of AOSP -->
+ <string name="app_ops_categories_location">Location</string>
+ <string name="app_ops_categories_personal">Personal</string>
+ <string name="app_ops_categories_messaging">Messaging</string>
+ <string name="app_ops_categories_media">Media</string>
+ <string name="app_ops_categories_device">Device</string>
+ <string name="app_ops_categories_run_in_background">Run in background</string>
+ <string name="app_ops_categories_bootup">Bootup</string>
+ <string name="app_ops_categories_su">Root access</string>
+ <string name="app_ops_categories_other">Other</string>
+
+ <!-- User display names for app ops codes - extension of AOSP -->
+ <string name="app_ops_summaries_accept_handover">handover of a call from another app</string>
+ <string name="app_ops_summaries_access_camera">access the camera</string>
+ <string name="app_ops_summaries_access_notifications">access notifications</string>
+ <string name="app_ops_summaries_activate_vpn">activate VPN</string>
+ <string name="app_ops_summaries_add_voicemail">add voicemail</string>
+ <string name="app_ops_summaries_app_start_foreground">start instant app in foreground</string>
+ <string name="app_ops_summaries_assist_screenshot">assist screenshot</string>
+ <string name="app_ops_summaries_assist_structure">assist structure</string>
+ <string name="app_ops_summaries_audio_accessibility_volume">audio accessibility volume</string>
+ <string name="app_ops_summaries_auto_start">start at power up</string>
+ <string name="app_ops_summaries_bind_accessibility_service">bind accessibility service</string>
+ <string name="app_ops_summaries_bluetooth_scan">bluetooth scan</string>
+ <string name="app_ops_summaries_change_wallpaper">change the wallpaper</string>
+ <string name="app_ops_summaries_coarse_location">coarse location</string>
+ <string name="app_ops_summaries_delete_call_log">delete your call log</string>
+ <string name="app_ops_summaries_delete_contacts">delete your contacts</string>
+ <string name="app_ops_summaries_delete_mms">delete your MMS messages</string>
+ <string name="app_ops_summaries_delete_sms">delete your SMS messages</string>
+ <string name="app_ops_summaries_draw_on_top">draw on top</string>
+ <string name="app_ops_summaries_fine_location">fine location</string>
+ <string name="app_ops_summaries_get_accounts">get accounts</string>
+ <string name="app_ops_summaries_get_usage_stats">get app usage stats</string>
+ <string name="app_ops_summaries_gps">GPS</string>
+ <string name="app_ops_summaries_install_packages">install packages</string>
+ <string name="app_ops_summaries_keep_device_awake">keep your device awake</string>
+ <string name="app_ops_summaries_make_phone_call">make a phone call</string>
+ <string name="app_ops_summaries_manage_ipsec_tunnels">manage ipsec tunnels</string>
+ <string name="app_ops_summaries_mock_location">mock location</string>
+ <string name="app_ops_summaries_modify_calendar">modify calendar</string>
+ <string name="app_ops_summaries_modify_call_log">modify call log</string>
+ <string name="app_ops_summaries_modify_clipboard">modify clipboard</string>
+ <string name="app_ops_summaries_modify_contacts">modify contacts</string>
+ <string name="app_ops_summaries_modify_settings">modify settings</string>
+ <string name="app_ops_summaries_monitor_high_power_location">monitor high power location</string>
+ <string name="app_ops_summaries_monitor_location">monitor location</string>
+ <string name="app_ops_summaries_mute_unmute_microphone">mute/unmute microphone</string>
+ <string name="app_ops_summaries_neighboring_cells">neighboring cells</string>
+ <string name="app_ops_summaries_phone_calls">answer phone calls</string>
+ <string name="app_ops_summaries_picture_in_picture">use picture in picture</string>
+ <string name="app_ops_summaries_play_audio">play audio</string>
+ <string name="app_ops_summaries_post_notification">post a notification</string>
+ <string name="app_ops_summaries_project_media">project media</string>
+ <string name="app_ops_summaries_read_calendar">read calendar</string>
+ <string name="app_ops_summaries_read_call_log">read call log</string>
+ <string name="app_ops_summaries_read_cell_broadcasts">read cell broadcasts</string>
+ <string name="app_ops_summaries_read_clipboard">read clipboard</string>
+ <string name="app_ops_summaries_read_contacts">read contacts</string>
+ <string name="app_ops_summaries_read_external_storage">read external storage</string>
+ <string name="app_ops_summaries_read_mms">read your MMS messages</string>
+ <string name="app_ops_summaries_read_phone_numbers">read phone numbers</string>
+ <string name="app_ops_summaries_read_phone_state">read phone state</string>
+ <string name="app_ops_summaries_read_sms">read SMS</string>
+ <string name="app_ops_summaries_receive_emergency_broadcast">receive an emergency broadcast message</string>
+ <string name="app_ops_summaries_receive_sms">receive SMS</string>
+ <string name="app_ops_summaries_record_audio">record audio</string>
+ <string name="app_ops_summaries_request_delete_packages">request delete packages</string>
+ <string name="app_ops_summaries_run_any_in_background">run any in background</string>
+ <string name="app_ops_summaries_run_in_background">run in background</string>
+ <string name="app_ops_summaries_scan_wifi">scan Wi-Fi networks</string>
+ <string name="app_ops_summaries_send_mms">send an MMS message</string>
+ <string name="app_ops_summaries_send_sms">send SMS</string>
+ <string name="app_ops_summaries_start_at_bootup">start at power up</string>
+ <string name="app_ops_summaries_start_foreground">start foreground</string>
+ <string name="app_ops_summaries_su">get root access</string>
+ <string name="app_ops_summaries_toast_window">display toasts</string>
+ <string name="app_ops_summaries_toggle_bluetooth">toggle Bluetooth</string>
+ <string name="app_ops_summaries_toggle_mobile_data">toggle cellular data</string>
+ <string name="app_ops_summaries_toggle_nfc">toggle NFC</string>
+ <string name="app_ops_summaries_toggle_wifi">toggle Wi-Fi</string>
+ <string name="app_ops_summaries_turn_on_screen">turn the screen on</string>
+ <string name="app_ops_summaries_use_alarm_volume">control alarm volume</string>
+ <string name="app_ops_summaries_use_audio_focus">control the audio focus</string>
+ <string name="app_ops_summaries_use_bluetooth_volume">control the Bluetooth volume</string>
+ <string name="app_ops_summaries_use_body_sensors">use body sensors</string>
+ <string name="app_ops_summaries_use_fingerprint">use fingerprint</string>
+ <string name="app_ops_summaries_use_master_volume">control the master volume</string>
+ <string name="app_ops_summaries_use_media_buttons">use the media buttons</string>
+ <string name="app_ops_summaries_use_media_volume">control the media volume</string>
+ <string name="app_ops_summaries_use_notification_volume">control the notification volume</string>
+ <string name="app_ops_summaries_use_ring_volume">control the ringtone volume</string>
+ <string name="app_ops_summaries_use_vibrate">use haptic feedback</string>
+ <string name="app_ops_summaries_use_voice_volume">control the voice call volume</string>
+ <string name="app_ops_summaries_wifi_change">change Wi-Fi state</string>
+ <string name="app_ops_summaries_write_external_storage">write to external storage</string>
+ <string name="app_ops_summaries_write_mms">write an MMS message</string>
+ <string name="app_ops_summaries_write_sms">write SMS</string>
+
+ <!-- User display names for app ops codes - extension of AOSP -->
+ <string name="app_ops_labels_accept_handover">Handover of a call from another app</string>
+ <string name="app_ops_labels_access_camera">Access the camera</string>
+ <string name="app_ops_labels_access_notifications">Access notifications</string>
+ <string name="app_ops_labels_activate_vpn">Activate VPN</string>
+ <string name="app_ops_labels_add_voicemail">Add voicemail</string>
+ <string name="app_ops_labels_app_start_foreground">Start instant app in foreground</string>
+ <string name="app_ops_labels_assist_screenshot">Assist screenshot</string>
+ <string name="app_ops_labels_assist_structure">Assist structure</string>
+ <string name="app_ops_labels_audio_accessibility_volume">Audio accessibility volume</string>
+ <string name="app_ops_labels_auto_start">Start at power up</string>
+ <string name="app_ops_labels_bind_accessibility_service">Bind accessibility service</string>
+ <string name="app_ops_labels_bluetooth_scan">Bluetooth scan</string>
+ <string name="app_ops_labels_change_wallpaper">Change the wallpaper</string>
+ <string name="app_ops_labels_coarse_location">Coarse location</string>
+ <string name="app_ops_labels_delete_call_log">Delete your call log</string>
+ <string name="app_ops_labels_delete_contacts">Delete your contacts</string>
+ <string name="app_ops_labels_delete_mms">Delete your MMS messages</string>
+ <string name="app_ops_labels_delete_sms">Delete your SMS messages</string>
+ <string name="app_ops_labels_draw_on_top">Draw on top</string>
+ <string name="app_ops_labels_fine_location">Fine location</string>
+ <string name="app_ops_labels_get_accounts">Get accounts</string>
+ <string name="app_ops_labels_get_usage_stats">Get usage stats</string>
+ <string name="app_ops_labels_gps">GPS</string>
+ <string name="app_ops_labels_install_packages">Install packages</string>
+ <string name="app_ops_labels_keep_device_awake">Keep your device awake</string>
+ <string name="app_ops_labels_make_phone_call">Make a phone call</string>
+ <string name="app_ops_labels_manage_ipsec_tunnels">Manage ipsec tunnels</string>
+ <string name="app_ops_labels_mock_location">Mock location</string>
+ <string name="app_ops_labels_modify_calendar">Modify calendar</string>
+ <string name="app_ops_labels_modify_call_log">Modify call log</string>
+ <string name="app_ops_labels_modify_clipboard">Modify clipboard</string>
+ <string name="app_ops_labels_modify_contacts">Modify contacts</string>
+ <string name="app_ops_labels_modify_settings">Modify settings</string>
+ <string name="app_ops_labels_monitor_high_power_location">Monitor high power location</string>
+ <string name="app_ops_labels_monitor_location">Monitor location</string>
+ <string name="app_ops_labels_mute_unmute_microphone">Mute/unmute microphone</string>
+ <string name="app_ops_labels_neighboring_cells">Neighboring cells</string>
+ <string name="app_ops_labels_phone_calls">Answer phone calls</string>
+ <string name="app_ops_labels_picture_in_picture">Use picture in picture</string>
+ <string name="app_ops_labels_play_audio">Play audio</string>
+ <string name="app_ops_labels_post_notification">Post a notification</string>
+ <string name="app_ops_labels_project_media">Project media</string>
+ <string name="app_ops_labels_read_calendar">Read calendar</string>
+ <string name="app_ops_labels_read_call_log">Read call log</string>
+ <string name="app_ops_labels_read_cell_broadcasts">Read cell broadcasts</string>
+ <string name="app_ops_labels_read_clipboard">Read clipboard</string>
+ <string name="app_ops_labels_read_contacts">Read contacts</string>
+ <string name="app_ops_labels_read_external_storage">Read external storage</string>
+ <string name="app_ops_labels_read_mms">Read your MMS messages</string>
+ <string name="app_ops_labels_read_phone_numbers">Read phone numbers</string>
+ <string name="app_ops_labels_read_phone_state">Read phone state</string>
+ <string name="app_ops_labels_read_sms">Read SMS</string>
+ <string name="app_ops_labels_receive_emergency_broadcast">Receive an emergency broadcast message</string>
+ <string name="app_ops_labels_receive_sms">Receive SMS</string>
+ <string name="app_ops_labels_record_audio">Record audio</string>
+ <string name="app_ops_labels_request_delete_packages">Request delete packages</string>
+ <string name="app_ops_labels_run_any_in_background">Run any in background</string>
+ <string name="app_ops_labels_run_in_background">Run in background</string>
+ <string name="app_ops_labels_scan_wifi">Scan Wi-Fi networks</string>
+ <string name="app_ops_labels_send_mms">Send an MMS message</string>
+ <string name="app_ops_labels_send_sms">Send SMS</string>
+ <string name="app_ops_labels_start_at_bootup">Start at power up</string>
+ <string name="app_ops_labels_start_foreground">Start foreground</string>
+ <string name="app_ops_labels_su">Get root access</string>
+ <string name="app_ops_labels_toast_window">Display toasts</string>
+ <string name="app_ops_labels_toggle_bluetooth">Toggle Bluetooth</string>
+ <string name="app_ops_labels_toggle_mobile_data">Toggle cellular data</string>
+ <string name="app_ops_labels_toggle_nfc">Toggle NFC</string>
+ <string name="app_ops_labels_toggle_wifi">Toggle Wi-Fi</string>
+ <string name="app_ops_labels_turn_on_screen">Turn the screen on</string>
+ <string name="app_ops_labels_use_alarm_volume">Control alarm volume</string>
+ <string name="app_ops_labels_use_audio_focus">Control the audio focus</string>
+ <string name="app_ops_labels_use_bluetooth_volume">Control the Bluetooth volume</string>
+ <string name="app_ops_labels_use_body_sensors">Use body sensors</string>
+ <string name="app_ops_labels_use_fingerprint">Use fingerprint</string>
+ <string name="app_ops_labels_use_master_volume">Control the master volume</string>
+ <string name="app_ops_labels_use_media_buttons">Use the media buttons</string>
+ <string name="app_ops_labels_use_media_volume">Control the media volume</string>
+ <string name="app_ops_labels_use_notification_volume">Control the notification volume</string>
+ <string name="app_ops_labels_use_ring_volume">Control the ringtone volume</string>
+ <string name="app_ops_labels_use_vibrate">Use haptic feedback</string>
+ <string name="app_ops_labels_use_voice_volume">Control the voice call volume</string>
+ <string name="app_ops_labels_wifi_change">Change Wi-Fi state</string>
+ <string name="app_ops_labels_write_external_storage">Write to external storage</string>
+ <string name="app_ops_labels_write_mms">Write an MMS message</string>
+ <string name="app_ops_labels_write_sms">Write SMS</string>
+
+ <!-- Setting checkbox title for root access -->
+ <string name="root_access">Root access</string>
+ <string name="root_access_warning_title">Allow root access?</string>
+ <string name="root_access_warning_message">Allowing apps to request root access is very dangerous and could compromise the security of your system!</string>
+ <string name="root_access_none">Disabled</string>
+ <string name="root_access_apps">Apps only</string>
+ <string name="root_access_adb">ADB only</string>
+ <string name="root_access_all">Apps and ADB</string>
+
+ <!-- Preference link for root appops -->
+ <string name="root_appops_title">Manage root accesses</string>
+ <string name="root_appops_summary">View and control the root rules</string>
+
+</resources>
diff --git a/res/values/fairphone_strings.xml b/res/values/fairphone_strings.xml
new file mode 100644
index 0000000..d5823bf
--- /dev/null
+++ b/res/values/fairphone_strings.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2021 Fairphone B.V.
+
+ 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="crypt_keeper_unsupported_text">
+ Encrypting the phone is currently not supported on Android 9 on the FP2. For
+ now, to encrypt the phone please install Android 7, encrypt, and upgrade to
+ Android 9 again.
+ </string>
+
+ <!-- Maintenance settings --> <skip />
+ <!-- Preference title for maintenance settings -->
+ <string name="maintenance_preference_title">Maintenance</string>
+ <!-- Maintenance settings screen, the title for the item to take the user to Checkup. -->
+ <string name="checkup_title" translatable="false">Checkup</string>
+ <!-- Maintenance settings screen, the summary for the item to take the user to Checkup. -->
+ <string name="checkup_summary">Hardware diagnostics</string>
+ <!-- Maintenance settings screen, the title for the item to take the user to the Proximity Sensor app. -->
+ <string name="proximity_sensor_title">Proximity sensor</string>
+ <!-- Maintenance settings screen, the summary for the item to take the user to the Proximity Sensor app. -->
+ <string name="proximity_sensor_summary">Calibrate the proximity sensor</string>
+ <!-- Maintenance settings screen, the title for the item to take the user to the Hiccup settings. -->
+ <string name="hiccup_title" translatable="false">Hiccup</string>
+ <!-- Maintenance settings screen, the summary for the item to take the user to the Hiccup settings. -->
+ <string name="hiccup_summary">Stability reporting</string>
+ <!-- Maintenance settings screen, the title for the item to take the user to the OpenGL ES settings. -->
+ <string name="fairphone_setting_title">Enhanced hardware features</string>
+ <!-- Maintenance settings screen, the summary for the item to take the user to the OpenGL ES settings. -->
+ <string name="fairphone_settings_summary">Enable OpenGL ES 3.0 and hardware video playback</string>
+
+ <!-- About --> <skip />
+ <!-- About phone, status item label. The hardware assembly number (set at the factory). -->
+ <string name="assembly_number">Assembly number</string>
+ <!-- About phone, status item label. The device's processor. -->
+ <string name="processor_info">Processor</string>
+ <!-- About phone, status item label. The installed receiver module. -->
+ <string name="receiver_module_info">Top module info</string>
+ <!-- About phone, status item value. Original receiver module with OV2685 sensor. -->
+ <string name="receiver_module_ov2685">Front camera 2MP – OmniVision OV2685</string>
+ <!-- About phone, status item value. 2017 receiver module with OV5670 sensor. -->
+ <string name="receiver_module_ov5670">Front camera 5MP – OmniVision OV5670</string>
+ <!-- About phone, status item label. The installed camera module. -->
+ <string name="camera_module_info">Camera module info</string>
+ <!-- About phone, status item value. Original camera module with OV8865 sensor. -->
+ <string name="camera_module_ov8865">Main camera 8MP – OmniVision OV8865</string>
+ <!-- About phone, status item value. 2017 camera module with OV12870 sensor. -->
+ <string name="camera_module_ov12870">Main camera 12MP – OmniVision OV12870</string>
+ <!-- About phone, status item label. The installed battery module. -->
+ <string name="battery_module_info">Battery info</string>
+ <!-- About phone, status item value. Battery module info. -->
+ <string name="battery_module_summary" translatable="false"><xliff:g id="version"
+ example="FP2-BAT01">%1$s</xliff:g> – <xliff:g id="capacity"
+ example="2420">%2$d</xliff:g> mAh</string>
+</resources>
diff --git a/res/values/lineage_arrays.xml b/res/values/lineage_arrays.xml
new file mode 100644
index 0000000..9377953
--- /dev/null
+++ b/res/values/lineage_arrays.xml
@@ -0,0 +1,403 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012-2015 The CyanogenMod Project
+ Copyright (C) 2018 The LinegeOS 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.
+-->
+<resources>
+ <!-- Arrays for root access capability -->
+ <string-array name="root_access_entries" translatable="false">
+ <item>@string/root_access_none</item>
+ <item>@string/root_access_apps</item>
+ <item>@string/root_access_adb</item>
+ <item>@string/root_access_all</item>
+ </string-array>
+
+ <string-array name="root_access_values" translatable="false">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ </string-array>
+
+ <string-array name="root_access_entries_adb" translatable="false">
+ <item>@string/root_access_none</item>
+ <item>@string/root_access_adb</item>
+ </string-array>
+
+ <string-array name="root_access_values_adb" translatable="false">
+ <item>0</item>
+ <item>2</item>
+ </string-array>
+
+ <!-- Names of categories of app ops tabs - extension of AOSP -->
+ <string-array name="app_ops_categories_lineage" translatable="false">
+ <item>@string/app_ops_categories_location</item>
+ <item>@string/app_ops_categories_personal</item>
+ <item>@string/app_ops_categories_messaging</item>
+ <item>@string/app_ops_categories_media</item>
+ <item>@string/app_ops_categories_device</item>
+ <item>@string/app_ops_categories_run_in_background</item>
+ <item>@string/app_ops_categories_bootup</item>
+ <item>@string/app_ops_categories_su</item>
+ <item>@string/app_ops_categories_other</item>
+ </string-array>
+
+ <!-- User display names for app ops codes - extension of AOSP -->
+ <string-array name="app_ops_summaries_lineage" translatable="false">
+ <!-- OP_COARSE_LOCATION -->
+ <item>@string/app_ops_summaries_coarse_location</item>
+ <!-- OP_FINE_LOCATION -->
+ <item>@string/app_ops_summaries_fine_location</item>
+ <!-- OP_GPS -->
+ <item>@string/app_ops_summaries_gps</item>
+ <!-- OP_VIBRATE -->
+ <item>@string/app_ops_summaries_use_vibrate</item>
+ <!-- OP_READ_CONTACTS -->
+ <item>@string/app_ops_summaries_read_contacts</item>
+ <!-- OP_WRITE_CONTACTS -->
+ <item>@string/app_ops_summaries_modify_contacts</item>
+ <!-- OP_READ_CALL_LOG -->
+ <item>@string/app_ops_summaries_read_call_log</item>
+ <!-- OP_WRITE_CALL_LOG -->
+ <item>@string/app_ops_summaries_modify_call_log</item>
+ <!-- OP_READ_CALENDAR -->
+ <item>@string/app_ops_summaries_read_calendar</item>
+ <!-- OP_WRITE_CALENDAR -->
+ <item>@string/app_ops_summaries_modify_calendar</item>
+ <!-- OP_WIFI_SCAN -->
+ <item>@string/app_ops_summaries_scan_wifi</item>
+ <!-- OP_POST_NOTIFICATION -->
+ <item>@string/app_ops_summaries_post_notification</item>
+ <!-- OP_NEIGHBORING_CELLS -->
+ <item>@string/app_ops_summaries_neighboring_cells</item>
+ <!-- OP_CALL_PHONE -->
+ <item>@string/app_ops_summaries_make_phone_call</item>
+ <!-- OP_READ_SMS -->
+ <item>@string/app_ops_summaries_read_sms</item>
+ <!-- OP_WRITE_SMS -->
+ <item>@string/app_ops_summaries_write_sms</item>
+ <!-- OP_RECEIVE_SMS -->
+ <item>@string/app_ops_summaries_receive_sms</item>
+ <!-- OPSTR_RECEIVE_EMERGENCY_BROADCAST -->
+ <item>@string/app_ops_summaries_receive_emergency_broadcast</item>
+ <!-- OP_RECEIVE_MMS -->
+ <item>@string/app_ops_summaries_receive_sms</item>
+ <!-- OP_RECEIVE_WAP_PUSH -->
+ <item>@string/app_ops_summaries_receive_sms</item>
+ <!-- OP_SEND_SMS -->
+ <item>@string/app_ops_summaries_send_sms</item>
+ <!-- OP_READ_ICC_SMS -->
+ <item>@string/app_ops_summaries_read_sms</item>
+ <!-- OP_WRITE_ICC_SMS -->
+ <item>@string/app_ops_summaries_write_sms</item>
+ <!-- OP_WRITE_SETTINGS -->
+ <item>@string/app_ops_summaries_modify_settings</item>
+ <!-- OP_SYSTEM_ALERT_WINDOW -->
+ <item>@string/app_ops_summaries_draw_on_top</item>
+ <!-- OP_ACCESS_NOTIFICATIONS -->
+ <item>@string/app_ops_summaries_access_notifications</item>
+ <!-- OP_CAMERA -->
+ <item>@string/app_ops_summaries_access_camera</item>
+ <!-- OP_RECORD_AUDIO -->
+ <item>@string/app_ops_summaries_record_audio</item>
+ <!-- OP_PLAY_AUDIO -->
+ <item>@string/app_ops_summaries_play_audio</item>
+ <!-- OP_READ_CLIPBOARD -->
+ <item>@string/app_ops_summaries_read_clipboard</item>
+ <!-- OP_WRITE_CLIPBOARD -->
+ <item>@string/app_ops_summaries_modify_clipboard</item>
+ <!-- OP_TAKE_MEDIA_BUTTONS -->
+ <item>@string/app_ops_summaries_use_media_buttons</item>
+ <!-- OP_TAKE_AUDIO_FOCUS -->
+ <item>@string/app_ops_summaries_use_audio_focus</item>
+ <!-- OP_AUDIO_MASTER_VOLUME -->
+ <item>@string/app_ops_summaries_use_master_volume</item>
+ <!-- OP_AUDIO_VOICE_VOLUME -->
+ <item>@string/app_ops_summaries_use_voice_volume</item>
+ <!-- OP_AUDIO_RING_VOLUME -->
+ <item>@string/app_ops_summaries_use_ring_volume</item>
+ <!-- OP_AUDIO_MEDIA_VOLUME -->
+ <item>@string/app_ops_summaries_use_media_volume</item>
+ <!-- OP_AUDIO_ALARM_VOLUME -->
+ <item>@string/app_ops_summaries_use_alarm_volume</item>
+ <!-- OP_AUDIO_NOTIFICATION_VOLUME -->
+ <item>@string/app_ops_summaries_use_notification_volume</item>
+ <!-- OP_AUDIO_BLUETOOTH_VOLUME -->
+ <item>@string/app_ops_summaries_use_bluetooth_volume</item>
+ <!-- OP_WAKE_LOCK -->
+ <item>@string/app_ops_summaries_keep_device_awake</item>
+ <!-- OP_MONITOR_LOCATION -->
+ <item>@string/app_ops_summaries_monitor_location</item>
+ <!-- OP_MONITOR_HIGH_POWER_LOCATION -->
+ <item>@string/app_ops_summaries_monitor_high_power_location</item>
+ <!-- OP_GET_USAGE_STATS -->
+ <item>@string/app_ops_summaries_get_usage_stats</item>
+ <!-- OP_MUTE_MICROPHONE -->
+ <item>@string/app_ops_summaries_mute_unmute_microphone</item>
+ <!-- OP_TOAST_WINDOW -->
+ <item>@string/app_ops_summaries_toast_window</item>
+ <!-- OP_PROJECT_MEDIA -->
+ <item>@string/app_ops_summaries_project_media</item>
+ <!-- OP_ACTIVATE_VPN -->
+ <item>@string/app_ops_summaries_activate_vpn</item>
+ <!-- OP_WRITE_WALLPAPER -->
+ <item>@string/app_ops_summaries_change_wallpaper</item>
+ <!-- OP_ASSIST_STRUCTURE -->
+ <item>@string/app_ops_summaries_assist_structure</item>
+ <!-- OP_ASSIST_SCREENSHOT -->
+ <item>@string/app_ops_summaries_assist_screenshot</item>
+ <!-- OP_READ_PHONE_STATE -->
+ <item>@string/app_ops_summaries_read_phone_state</item>
+ <!-- OP_ADD_VOICEMAIL -->
+ <item>@string/app_ops_summaries_add_voicemail</item>
+ <!-- OP_USE_SIP -->
+ <item>@string/app_ops_summaries_make_phone_call</item>
+ <!-- OP_PROCESS_OUTGOING_CALLS -->
+ <item>@string/app_ops_summaries_make_phone_call</item>
+ <!-- OP_USE_FINGERPRINT -->
+ <item>@string/app_ops_summaries_use_fingerprint</item>
+ <!-- OP_BODY_SENSORS -->
+ <item>@string/app_ops_summaries_use_body_sensors</item>
+ <!-- OP_READ_CELL_BROADCASTS -->
+ <item>@string/app_ops_summaries_read_cell_broadcasts</item>
+ <!-- OP_MOCK_LOCATION -->
+ <item>@string/app_ops_summaries_mock_location</item>
+ <!-- OP_READ_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_summaries_read_external_storage</item>
+ <!-- OP_WRITE_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_summaries_write_external_storage</item>
+ <!-- OP_TURN_SCREEN_ON -->
+ <item>@string/app_ops_summaries_turn_on_screen</item>
+ <!-- OP_GET_ACCOUNTS -->
+ <item>@string/app_ops_summaries_get_accounts</item>
+ <!-- OP_RUN_IN_BACKGROUND -->
+ <item>@string/app_ops_summaries_run_in_background</item>
+ <!-- OP_AUDIO_ACCESSIBILITY_VOLUME -->
+ <item>@string/app_ops_summaries_audio_accessibility_volume</item>
+ <!-- OP_READ_PHONE_NUMBERS -->
+ <item>@string/app_ops_summaries_read_phone_numbers</item>
+ <!-- OP_REQUEST_INSTALL_PACKAGES -->
+ <item>@string/app_ops_summaries_install_packages</item>
+ <!-- OP_PICTURE_IN_PICTURE -->
+ <item>@string/app_ops_summaries_picture_in_picture</item>
+ <!-- OP_INSTANT_APP_START_FOREGROUND -->
+ <item>@string/app_ops_summaries_app_start_foreground</item>
+ <!-- OP_ANSWER_PHONE_CALLS -->
+ <item>@string/app_ops_summaries_phone_calls</item>
+ <!-- OP_RUN_ANY_IN_BACKGROUND -->
+ <item>@string/app_ops_summaries_run_any_in_background</item>
+ <!-- OP_CHANGE_WIFI_STATE -->
+ <item>@string/app_ops_summaries_wifi_change</item>
+ <!-- OP_REQUEST_DELETE_PACKAGES -->
+ <item>@string/app_ops_summaries_request_delete_packages</item>
+ <!-- OP_BIND_ACCESSIBILITY_SERVICE -->
+ <item>@string/app_ops_summaries_bind_accessibility_service</item>
+ <!-- OP_ACCEPT_HANDOVER -->
+ <item>@string/app_ops_summaries_accept_handover</item>
+ <!-- OP_MANAGE_IPSEC_TUNNELS -->
+ <item>@string/app_ops_summaries_manage_ipsec_tunnels</item>
+ <!-- OP_START_FOREGROUND -->
+ <item>@string/app_ops_summaries_start_foreground</item>
+ <!-- OP_BLUETOOTH_SCAN -->
+ <item>@string/app_ops_summaries_bluetooth_scan</item>
+ <!-- OP_BLUETOOTH_CHANGE -->
+ <item>@string/app_ops_summaries_toggle_bluetooth</item>
+ <!-- OP_BOOT_COMPLETED -->
+ <item>@string/app_ops_summaries_start_at_bootup</item>
+ <!-- OP_NFC_CHANGE -->
+ <item>@string/app_ops_summaries_toggle_nfc</item>
+ <!-- OP_DATA_CONNECT_CHANGE -->
+ <item>@string/app_ops_summaries_toggle_mobile_data</item>
+ <!-- OP_SU -->
+ <item>@string/app_ops_summaries_su</item>
+ </string-array>
+
+ <!-- User display names for app ops codes - extension of AOSP -->
+ <string-array name="app_ops_labels_lineage" translatable="false">
+ <!-- OP_COARSE_LOCATION -->
+ <item>@string/app_ops_labels_coarse_location</item>
+ <!-- OP_FINE_LOCATION -->
+ <item>@string/app_ops_labels_fine_location</item>
+ <!-- OP_GPS -->
+ <item>@string/app_ops_labels_gps</item>
+ <!-- OP_VIBRATE -->
+ <item>@string/app_ops_labels_use_vibrate</item>
+ <!-- OP_READ_CONTACTS -->
+ <item>@string/app_ops_labels_read_contacts</item>
+ <!-- OP_WRITE_CONTACTS -->
+ <item>@string/app_ops_labels_modify_contacts</item>
+ <!-- OP_READ_CALL_LOG -->
+ <item>@string/app_ops_labels_read_call_log</item>
+ <!-- OP_WRITE_CALL_LOG -->
+ <item>@string/app_ops_labels_modify_call_log</item>
+ <!-- OP_READ_CALENDAR -->
+ <item>@string/app_ops_labels_read_calendar</item>
+ <!-- OP_WRITE_CALENDAR -->
+ <item>@string/app_ops_labels_modify_calendar</item>
+ <!-- OP_WIFI_SCAN -->
+ <item>@string/app_ops_labels_scan_wifi</item>
+ <!-- OP_POST_NOTIFICATION -->
+ <item>@string/app_ops_labels_post_notification</item>
+ <!-- OP_NEIGHBORING_CELLS -->
+ <item>@string/app_ops_labels_neighboring_cells</item>
+ <!-- OP_CALL_PHONE -->
+ <item>@string/app_ops_labels_make_phone_call</item>
+ <!-- OP_READ_SMS -->
+ <item>@string/app_ops_labels_read_sms</item>
+ <!-- OP_WRITE_SMS -->
+ <item>@string/app_ops_labels_write_sms</item>
+ '<!-- OP_RECEIVE_SMS -->
+ <item>@string/app_ops_labels_receive_sms</item>
+ <!-- OPSTR_RECEIVE_EMERGENCY_BROADCAST -->
+ <item>@string/app_ops_labels_receive_emergency_broadcast</item>
+ <!-- OP_RECEIVE_MMS -->
+ <item>@string/app_ops_labels_receive_sms</item>
+ <!-- OP_RECEIVE_WAP_PUSH -->
+ <item>@string/app_ops_labels_receive_sms</item>
+ <!-- OP_SEND_SMS -->
+ <item>@string/app_ops_labels_send_sms</item>
+ <!-- OP_READ_ICC_SMS -->
+ <item>@string/app_ops_labels_read_sms</item>
+ <!-- OP_WRITE_ICC_SMS -->
+ <item>@string/app_ops_labels_write_sms</item>
+ <!-- OP_WRITE_SETTINGS -->
+ <item>@string/app_ops_labels_modify_settings</item>
+ <!-- OP_SYSTEM_ALERT_WINDOW -->
+ <item>@string/app_ops_labels_draw_on_top</item>
+ <!-- OP_ACCESS_NOTIFICATIONS -->
+ <item>@string/app_ops_labels_access_notifications</item>
+ <!-- OP_CAMERA -->
+ <item>@string/app_ops_labels_access_camera</item>
+ <!-- OP_RECORD_AUDIO -->
+ <item>@string/app_ops_labels_record_audio</item>
+ <!-- OP_PLAY_AUDIO -->
+ <item>@string/app_ops_labels_play_audio</item>
+ <!-- OP_READ_CLIPBOARD -->
+ <item>@string/app_ops_labels_read_clipboard</item>
+ <!-- OP_WRITE_CLIPBOARD -->
+ <item>@string/app_ops_labels_modify_clipboard</item>
+ <!-- OP_TAKE_MEDIA_BUTTONS -->
+ <item>@string/app_ops_labels_use_media_buttons</item>
+ <!-- OP_TAKE_AUDIO_FOCUS -->
+ <item>@string/app_ops_labels_use_audio_focus</item>
+ <!-- OP_AUDIO_MASTER_VOLUME -->
+ <item>@string/app_ops_labels_use_master_volume</item>
+ <!-- OP_AUDIO_VOICE_VOLUME -->
+ <item>@string/app_ops_labels_use_voice_volume</item>
+ <!-- OP_AUDIO_RING_VOLUME -->
+ <item>@string/app_ops_labels_use_ring_volume</item>
+ <!-- OP_AUDIO_MEDIA_VOLUME -->
+ <item>@string/app_ops_labels_use_media_volume</item>
+ <!-- OP_AUDIO_ALARM_VOLUME -->
+ <item>@string/app_ops_labels_use_alarm_volume</item>
+ <!-- OP_AUDIO_NOTIFICATION_VOLUME -->
+ <item>@string/app_ops_labels_use_notification_volume</item>
+ <!-- OP_AUDIO_BLUETOOTH_VOLUME -->
+ <item>@string/app_ops_labels_use_bluetooth_volume</item>
+ <!-- OP_WAKE_LOCK -->
+ <item>@string/app_ops_labels_keep_device_awake</item>
+ <!-- OP_MONITOR_LOCATION -->
+ <item>@string/app_ops_labels_monitor_location</item>
+ <!-- OP_MONITOR_HIGH_POWER_LOCATION -->
+ <item>@string/app_ops_labels_monitor_high_power_location</item>
+ <!-- OP_GET_USAGE_STATS -->
+ <item>@string/app_ops_labels_get_usage_stats</item>
+ <!-- OP_MUTE_MICROPHONE -->
+ <item>@string/app_ops_labels_mute_unmute_microphone</item>
+ <!-- OP_TOAST_WINDOW -->
+ <item>@string/app_ops_labels_toast_window</item>
+ <!-- OP_PROJECT_MEDIA -->
+ <item>@string/app_ops_labels_project_media</item>
+ <!-- OP_ACTIVATE_VPN -->
+ <item>@string/app_ops_labels_activate_vpn</item>
+ <!-- OP_WRITE_WALLPAPER -->
+ <item>@string/app_ops_labels_change_wallpaper</item>
+ <!-- OP_ASSIST_STRUCTURE -->
+ <item>@string/app_ops_labels_assist_structure</item>
+ <!-- OP_ASSIST_SCREENSHOT -->
+ <item>@string/app_ops_labels_assist_screenshot</item>
+ <!-- OP_READ_PHONE_STATE -->
+ <item>@string/app_ops_labels_read_phone_state</item>
+ <!-- OP_ADD_VOICEMAIL -->
+ <item>@string/app_ops_labels_add_voicemail</item>
+ <!-- OP_USE_SIP -->
+ <item>@string/app_ops_labels_make_phone_call</item>
+ <!-- OP_PROCESS_OUTGOING_CALLS -->
+ <item>@string/app_ops_labels_make_phone_call</item>
+ <!-- OP_USE_FINGERPRINT -->
+ <item>@string/app_ops_labels_use_fingerprint</item>
+ <!-- OP_BODY_SENSORS -->
+ <item>@string/app_ops_labels_use_body_sensors</item>
+ <!-- OP_READ_CELL_BROADCASTS -->
+ <item>@string/app_ops_labels_read_cell_broadcasts</item>
+ <!-- OP_MOCK_LOCATION -->
+ <item>@string/app_ops_labels_mock_location</item>
+ <!-- OP_READ_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_labels_read_external_storage</item>
+ <!-- OP_WRITE_EXTERNAL_STORAGE -->
+ <item>@string/app_ops_labels_write_external_storage</item>
+ <!-- OP_TURN_SCREEN_ON -->
+ <item>@string/app_ops_labels_turn_on_screen</item>
+ <!-- OP_GET_ACCOUNTS -->
+ <item>@string/app_ops_labels_get_accounts</item>
+ <!-- OP_RUN_IN_BACKGROUND -->
+ <item>@string/app_ops_labels_run_in_background</item>
+ <!-- OP_AUDIO_ACCESSIBILITY_VOLUME -->
+ <item>@string/app_ops_labels_audio_accessibility_volume</item>
+ <!-- OP_READ_PHONE_NUMBERS -->
+ <item>@string/app_ops_labels_read_phone_numbers</item>
+ <!-- OP_REQUEST_INSTALL_PACKAGES -->
+ <item>@string/app_ops_labels_install_packages</item>
+ <!-- OP_PICTURE_IN_PICTURE -->
+ <item>@string/app_ops_labels_picture_in_picture</item>
+ <!-- OP_INSTANT_APP_START_FOREGROUND -->
+ <item>@string/app_ops_labels_app_start_foreground</item>
+ <!-- OP_ANSWER_PHONE_CALLS -->
+ <item>@string/app_ops_labels_phone_calls</item>
+ <!-- OP_RUN_ANY_IN_BACKGROUND -->
+ <item>@string/app_ops_labels_run_any_in_background</item>
+ <!-- OP_CHANGE_WIFI_STATE -->
+ <item>@string/app_ops_labels_wifi_change</item>
+ <!-- OP_REQUEST_DELETE_PACKAGES -->
+ <item>@string/app_ops_labels_request_delete_packages</item>
+ <!-- OP_BIND_ACCESSIBILITY_SERVICE -->
+ <item>@string/app_ops_labels_bind_accessibility_service</item>
+ <!-- OP_ACCEPT_HANDOVER -->
+ <item>@string/app_ops_labels_accept_handover</item>
+ <!-- OP_MANAGE_IPSEC_TUNNELS -->
+ <item>@string/app_ops_labels_manage_ipsec_tunnels</item>
+ <!-- OP_START_FOREGROUND -->
+ <item>@string/app_ops_labels_start_foreground</item>
+ <!-- OP_BLUETOOTH_SCAN -->
+ <item>@string/app_ops_labels_bluetooth_scan</item>
+ <!-- OP_BLUETOOTH_CHANGE -->
+ <item>@string/app_ops_labels_toggle_bluetooth</item>
+ <!-- OP_BOOT_COMPLETED -->
+ <item>@string/app_ops_labels_start_at_bootup</item>
+ <!-- OP_NFC_CHANGE -->
+ <item>@string/app_ops_labels_toggle_nfc</item>
+ <!-- OP_DATA_CONNECT_CHANGE -->
+ <item>@string/app_ops_labels_toggle_mobile_data</item>
+ <!-- OP_SU -->
+ <item>@string/app_ops_labels_su</item>
+ </string-array>
+
+ <!-- App ops permissions -->
+ <string-array name="app_ops_permissions">
+ <item>@string/app_ops_permissions_allowed</item>
+ <item>@string/app_ops_permissions_ignored</item>
+ <item>@string/app_ops_permissions_always_ask</item>
+ </string-array>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cc6d65c..56acccf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10093,4 +10093,7 @@
<string name="bluetooth_phonebook_access_dialog_title">Allow access to contacts and call log?</string>
<!-- Bluetooth phonebook permission alert for dialog content [CHAR LIMIT=none] -->
<string name="bluetooth_phonebook_access_dialog_content">An untrusted Bluetooth device, <xliff:g id="device_name" example="My device">%1$s</xliff:g>, wants to access your contacts and call log. This includes data about incoming and outgoing calls.\n\nYou haven\u2019t connected to <xliff:g id="device_name" example="My device">%2$s</xliff:g> before.</string>
+
+ <!-- Privacy Guard -->
+ <string name="privacy_guard_manager_title">Privacy Guard</string>
</resources>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 74f29b3..e1dd978 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -119,6 +119,16 @@
android:key="quick_settings_tiles"
android:title="@string/quick_settings_developer_tiles"
android:fragment="com.android.settings.development.qstile.DevelopmentTileConfigFragment" />
+
+ <ListPreference
+ android:key="root_access"
+ android:title="@string/root_access"
+ android:persistent="false" />
+
+ <Preference
+ android:key="root_appops"
+ android:title="@string/root_appops_title"
+ android:summary="@string/root_appops_summary" />
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/maintenance.xml b/res/xml/maintenance.xml
new file mode 100644
index 0000000..ebe93e4
--- /dev/null
+++ b/res/xml/maintenance.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018-2020 Fairphone B.V.
+
+ 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-auto"
+ android:key="maintenance_settings_screen"
+ android:title="@string/maintenance_preference_title">
+
+ <Preference
+ android:key="checkup"
+ android:title="@string/checkup_title"
+ android:summary="@string/checkup_summary">
+
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.fairphone.checkup"
+ android:targetClass="com.fairphone.checkup.MainActivity" />
+
+ </Preference>
+
+ <Preference
+ android:key="proximity_sensor"
+ android:title="@string/proximity_sensor_title"
+ android:summary="@string/proximity_sensor_summary">
+
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.fairphone.psensor"
+ android:targetClass="com.fairphone.psensor.CalibrationActivity" />
+
+ </Preference>
+
+ <Preference
+ android:key="hiccup"
+ android:title="@string/hiccup_title"
+ android:summary="@string/hiccup_summary">
+
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.fairphone.hiccup.app"
+ android:targetClass="com.fairphone.hiccup.app.HiccupSettings" />
+
+ </Preference>
+
+ <Preference
+ android:key="opengles3"
+ android:title="@string/fairphone_setting_title"
+ android:summary="@string/fairphone_settings_summary">
+
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.fairphone.fp2.settings"
+ android:targetClass="com.fairphone.fp2.settings.ui.FairphoneSettingsActivity" />
+
+ </Preference>
+
+</PreferenceScreen>
diff --git a/res/xml/process_stats_summary.xml b/res/xml/process_stats_summary.xml
index 3b3271d..0e62f5c 100644
--- a/res/xml/process_stats_summary.xml
+++ b/res/xml/process_stats_summary.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2015-2016 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.
@@ -60,4 +62,8 @@
android:key="apps_list"
android:title="@string/memory_usage_apps" />
+ <Preference
+ android:key="apps_startup"
+ android:title="@string/memory_startup_apps_title" />
+
</PreferenceScreen>
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
new file mode 100644
index 0000000..878167f
--- /dev/null
+++ b/res/xml/security_settings_misc.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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:lineage="http://schemas.android.com/apk/res/lineageos.platform"
+ android:title="@string/security_settings_title">
+
+ <PreferenceCategory android:title="@string/security_passwords_title"
+ android:persistent="false">
+
+ <Preference
+ android:key="location"
+ android:title="@string/location_settings_title"
+ android:fragment="com.android.settings.location.LocationSettings">
+ </Preference>
+
+ <SwitchPreference
+ android:key="show_password"
+ android:title="@string/show_password"
+ android:summary="@string/show_password_summary"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory>
+
+ <Preference android:key="manage_device_admin"
+ android:title="@string/manage_device_admin"
+ android:persistent="false"
+ android:fragment="com.android.settings.DeviceAdminSettings"/>
+
+ <Preference android:key="enterprise_privacy"
+ android:title="@string/enterprise_privacy_settings"
+ android:persistent="false"
+ android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"/>
+
+ </PreferenceCategory>
+
+ <Preference android:key="sim_lock_settings"
+ android:title="@string/sim_lock_settings_category"
+ android:persistent="false">
+
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.android.settings"
+ android:targetClass="com.android.settings.Settings$IccLockSettingsActivity"/>
+
+ </Preference>
+
+ <Preference
+ android:key="encryption_and_credential"
+ android:title="@string/encryption_and_credential_settings_title"
+ android:summary="@string/encryption_and_credential_settings_summary"
+ android:fragment="com.android.settings.EncryptionAndCredential"/>
+
+ <Preference android:key="manage_trust_agents"
+ android:title="@string/manage_trust_agents"
+ android:persistent="false"
+ android:fragment="com.android.settings.TrustAgentSettings"/>
+
+ <Preference
+ android:key="screen_pinning_settings"
+ android:title="@string/screen_pinning_title"
+ android:summary="@string/switch_off_text"
+ android:fragment="com.android.settings.ScreenPinningSettings"/>
+
+ <Preference android:key="usage_access"
+ android:title="@string/usage_access_title"
+ android:fragment="com.android.settings.applications.ManageApplications">
+ <extra
+ android:name="classname"
+ android:value="com.android.settings.Settings$UsageAccessSettingsActivity" />
+ </Preference>
+
+</PreferenceScreen>
diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml
index 1ca86ab..e86c8f0 100644
--- a/res/xml/system_dashboard_fragment.xml
+++ b/res/xml/system_dashboard_fragment.xml
@@ -19,7 +19,7 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="system_dashboard_screen"
android:title="@string/header_category_system"
- settings:initialExpandedChildrenCount="4">
+ settings:initialExpandedChildrenCount="5">
<Preference
android:key="gesture_settings"
@@ -29,6 +29,13 @@
android:fragment="com.android.settings.gestures.GestureSettings"
settings:controller="com.android.settings.gestures.GesturesSettingPreferenceController"/>
+ <Preference
+ android:key="maintenance_settings"
+ android:title="@string/maintenance_preference_title"
+ android:icon="@drawable/ic_settings_maintenance"
+ android:order="-240"
+ android:fragment="com.android.settings.MaintenanceSettings"/>
+
<!-- Backup -->
<Preference
android:key="backup_settings"
@@ -58,7 +65,9 @@
android:order="-30"
settings:keywords="@string/keywords_system_update_settings"
settings:controller="com.android.settings.system.SystemUpdatePreferenceController">
- <intent android:action="android.settings.SYSTEM_UPDATE_SETTINGS" />
+ <intent android:action="android.intent.action.MAIN"
+ android:targetPackage="com.fairphone.updater"
+ android:targetClass="com.fairphone.updater.UpdaterActivity" />
</Preference>
<Preference
diff --git a/src/com/android/settings/MaintenanceSettings.java b/src/com/android/settings/MaintenanceSettings.java
new file mode 100644
index 0000000..46a9f84
--- /dev/null
+++ b/src/com/android/settings/MaintenanceSettings.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018-2020 Fairphone B.V.
+ *
+ * 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;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+
+public class MaintenanceSettings extends DashboardFragment {
+
+ private static final String TAG = "MaintenanceSettings";
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.FP_MAINTENANCE;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.maintenance;
+ }
+}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 0ad964b..95d42ed 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
+import com.android.settings.applications.appops.AppOpsSummary;
import com.android.settings.enterprise.EnterprisePrivacySettings;
/**
@@ -56,6 +57,15 @@
public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
public static class ManageAssistActivity extends SettingsActivity { /* empty */ }
public static class HighPowerApplicationsActivity extends SettingsActivity { /* empty */ }
+ public static class AppOpsSummaryActivity extends SettingsActivity {
+ @Override
+ public boolean isValidFragment(String className) {
+ if (AppOpsSummary.class.getName().equals(className)) {
+ return true;
+ }
+ return super.isValidFragment(className);
+ }
+ }
public static class BackgroundCheckSummaryActivity extends SettingsActivity { /* empty */ }
public static class StorageUseActivity extends SettingsActivity { /* empty */ }
public static class DevelopmentSettingsDashboardActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/applications/ProcessStatsSummary.java b/src/com/android/settings/applications/ProcessStatsSummary.java
index 53da04c..de091d0 100644
--- a/src/com/android/settings/applications/ProcessStatsSummary.java
+++ b/src/com/android/settings/applications/ProcessStatsSummary.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -17,6 +18,7 @@
import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
@@ -25,12 +27,15 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.Settings.AppOpsSummaryActivity;
import com.android.settings.SummaryPreference;
import com.android.settings.Utils;
import com.android.settings.applications.ProcStatsData.MemInfo;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.SummaryLoader;
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
+
public class ProcessStatsSummary extends ProcessStatsBase implements OnPreferenceClickListener {
private static final String KEY_STATUS_HEADER = "status_header";
@@ -40,6 +45,7 @@
private static final String KEY_AVERAGY_USED = "average_used";
private static final String KEY_FREE = "free";
private static final String KEY_APP_LIST = "apps_list";
+ private static final String KEY_APP_STARTUP = "apps_startup";
private SummaryPreference mSummaryPref;
@@ -48,6 +54,7 @@
private Preference mAverageUsed;
private Preference mFree;
private Preference mAppListPreference;
+ private Preference mAppStartupPreference;
@Override
public void onCreate(Bundle icicle) {
@@ -61,6 +68,8 @@
mFree = findPreference(KEY_FREE);
mAppListPreference = findPreference(KEY_APP_LIST);
mAppListPreference.setOnPreferenceClickListener(this);
+ mAppStartupPreference = findPreference(KEY_APP_STARTUP);
+ mAppStartupPreference.setOnPreferenceClickListener(this);
}
@Override
@@ -123,6 +132,14 @@
.setSourceMetricsCategory(getMetricsCategory())
.launch();
return true;
+ } else if (preference == mAppStartupPreference) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ Bundle args = new Bundle();
+ args.putString("appops_tab", getString(R.string.app_ops_categories_bootup));
+ intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
+ intent.setClass(getContext(), AppOpsSummaryActivity.class);
+ startActivity(intent);
+ return true;
}
return false;
}
diff --git a/src/com/android/settings/applications/appops/AppOpsCategory.java b/src/com/android/settings/applications/appops/AppOpsCategory.java
index b506ce0..aa2f878 100644
--- a/src/com/android/settings/applications/appops/AppOpsCategory.java
+++ b/src/com/android/settings/applications/appops/AppOpsCategory.java
@@ -38,25 +38,40 @@
import android.widget.Switch;
import android.widget.TextView;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.applications.appops.AppOpsState.AppOpEntry;
+import com.android.settings.core.SubSettingLauncher;
import java.util.List;
public class AppOpsCategory extends ListFragment implements
LoaderManager.LoaderCallbacks<List<AppOpEntry>> {
+ private static final String LOG_TAG = "SettingsActivity";
+
+ private static final int RESULT_APP_DETAILS = 1;
+
AppOpsState mState;
+ boolean mUserControlled;
// This is the Adapter being used to display the list's data.
AppListAdapter mAdapter;
+ String mCurrentPkgName;
+
public AppOpsCategory() {
}
public AppOpsCategory(AppOpsState.OpsTemplate template) {
+ this(template, false);
+ }
+
+ public AppOpsCategory(AppOpsState.OpsTemplate template, boolean userControlled) {
Bundle args = new Bundle();
args.putParcelable("template", template);
+ args.putBoolean("userControlled", userControlled);
setArguments(args);
}
@@ -114,18 +129,22 @@
final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
final AppOpsState mState;
final AppOpsState.OpsTemplate mTemplate;
+ final boolean mUserControlled;
List<AppOpEntry> mApps;
PackageIntentReceiver mPackageObserver;
- public AppListLoader(Context context, AppOpsState state, AppOpsState.OpsTemplate template) {
+ public AppListLoader(Context context, AppOpsState state, AppOpsState.OpsTemplate template,
+ boolean userControlled) {
super(context);
mState = state;
mTemplate = template;
+ mUserControlled = userControlled;
}
@Override public List<AppOpEntry> loadInBackground() {
- return mState.buildState(mTemplate, 0, null, AppOpsState.LABEL_COMPARATOR);
+ return mState.buildState(mTemplate, 0, null, mUserControlled ?
+ AppOpsState.LABEL_COMPARATOR : AppOpsState.RECENCY_COMPARATOR);
}
/**
@@ -244,13 +263,15 @@
private final Resources mResources;
private final LayoutInflater mInflater;
private final AppOpsState mState;
+ private final boolean mUserControlled;
List<AppOpEntry> mList;
- public AppListAdapter(Context context, AppOpsState state) {
+ public AppListAdapter(Context context, AppOpsState state, boolean userControlled) {
mResources = context.getResources();
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mState = state;
+ mUserControlled = userControlled;
}
public void setData(List<AppOpEntry> data) {
@@ -290,11 +311,18 @@
((ImageView) view.findViewById(R.id.app_icon)).setImageDrawable(
item.getAppEntry().getIcon());
((TextView) view.findViewById(R.id.app_name)).setText(item.getAppEntry().getLabel());
- ((TextView) view.findViewById(R.id.op_name)).setText(
- item.getTimeText(mResources, false));
- view.findViewById(R.id.op_time).setVisibility(View.GONE);
- ((Switch) view.findViewById(R.id.op_switch)).setChecked(
- item.getPrimaryOpMode() == AppOpsManager.MODE_ALLOWED);
+ if (mUserControlled) {
+ ((TextView) view.findViewById(R.id.op_name)).setText(
+ item.getTimeText(mResources, false));
+ view.findViewById(R.id.op_time).setVisibility(View.GONE);
+ ((Switch) view.findViewById(R.id.op_switch)).setChecked(
+ item.getPrimaryOpMode() == AppOpsManager.MODE_ALLOWED);
+ } else {
+ ((TextView) view.findViewById(R.id.op_name)).setText(item.getSummaryText(mState));
+ ((TextView) view.findViewById(R.id.op_time)).setText(
+ item.getTimeText(mResources, false));
+ view.findViewById(R.id.op_switch).setVisibility(View.GONE);
+ }
return view;
}
@@ -304,6 +332,7 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mState = new AppOpsState(getActivity());
+ mUserControlled = getArguments().getBoolean("userControlled");
}
@Override public void onActivityCreated(Bundle savedInstanceState) {
@@ -317,7 +346,7 @@
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
- mAdapter = new AppListAdapter(getActivity(), mState);
+ mAdapter = new AppListAdapter(getActivity(), mState, mUserControlled);
setListAdapter(mAdapter);
// Start out with a progress indicator.
@@ -327,20 +356,40 @@
getLoaderManager().initLoader(0, null, this);
}
+ // utility method used to start sub activity
+ private void startApplicationDetailsActivity() {
+ // start new fragment to display extended information
+ final Bundle args = new Bundle();
+ args.putString(AppOpsDetails.ARG_PACKAGE_NAME, mCurrentPkgName);
+
+ new SubSettingLauncher(getContext())
+ .setDestination(AppOpsDetails.class.getName())
+ .setTitle(R.string.privacy_guard_manager_title)
+ .setArguments(args)
+ .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN)
+ .setResultListener(this, RESULT_APP_DETAILS)
+ .launch();
+ }
+
@Override public void onListItemClick(ListView l, View v, int position, long id) {
AppOpEntry entry = mAdapter.getItem(position);
if (entry != null) {
- // We treat this as tapping on the check box, toggling the app op state.
- Switch sw = v.findViewById(R.id.op_switch);
- boolean checked = !sw.isChecked();
- sw.setChecked(checked);
- AppOpsManager.OpEntry op = entry.getOpEntry(0);
- int mode = checked ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
- mState.getAppOpsManager().setMode(op.getOp(),
- entry.getAppEntry().getApplicationInfo().uid,
- entry.getAppEntry().getApplicationInfo().packageName,
- mode);
- entry.overridePrimaryOpMode(mode);
+ if (mUserControlled) {
+ // We treat this as tapping on the check box, toggling the app op state.
+ Switch sw = ((Switch) v.findViewById(R.id.op_switch));
+ boolean checked = !sw.isChecked();
+ sw.setChecked(checked);
+ AppOpsManager.OpEntry op = entry.getOpEntry(0);
+ int mode = checked ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+ mState.getAppOpsManager().setMode(op.getOp(),
+ entry.getAppEntry().getApplicationInfo().uid,
+ entry.getAppEntry().getApplicationInfo().packageName,
+ mode);
+ entry.overridePrimaryOpMode(mode);
+ } else {
+ mCurrentPkgName = entry.getAppEntry().getApplicationInfo().packageName;
+ startApplicationDetailsActivity();
+ }
}
}
@@ -348,9 +397,9 @@
Bundle fargs = getArguments();
AppOpsState.OpsTemplate template = null;
if (fargs != null) {
- template = fargs.getParcelable("template");
+ template = (AppOpsState.OpsTemplate) fargs.getParcelable("template");
}
- return new AppListLoader(getActivity(), mState, template);
+ return new AppListLoader(getActivity(), mState, template, mUserControlled);
}
@Override public void onLoadFinished(Loader<List<AppOpEntry>> loader, List<AppOpEntry> data) {
diff --git a/src/com/android/settings/applications/appops/AppOpsDetails.java b/src/com/android/settings/applications/appops/AppOpsDetails.java
new file mode 100644
index 0000000..72bc38f
--- /dev/null
+++ b/src/com/android/settings/applications/appops/AppOpsDetails.java
@@ -0,0 +1,406 @@
+/**
+ * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017-2018 The LineageOS 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.applications.appops;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.Utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringJoiner;
+
+public class AppOpsDetails extends SettingsPreferenceFragment {
+ static final String TAG = "AppOpsDetails";
+
+ public static final String ARG_PACKAGE_NAME = "package";
+ private static final String KEY_HEADER = "header";
+
+ private AppOpsState mState;
+ private PackageManager mPm;
+ private AppOpsManager mAppOps;
+ private PackageInfo mPackageInfo;
+ private PreferenceScreen mPreferenceScreen;
+
+ private final int MODE_ALLOWED = 0;
+ private final int MODE_IGNORED = 1;
+ private final int MODE_ASK = 2;
+
+ private final String[] MODE_ENTRIES = {
+ String.valueOf(MODE_ALLOWED),
+ String.valueOf(MODE_IGNORED),
+ String.valueOf(MODE_ASK)
+ };
+
+ private int modeToPosition(int mode) {
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return MODE_ALLOWED;
+ case AppOpsManager.MODE_IGNORED:
+ return MODE_IGNORED;
+ case AppOpsManager.MODE_ASK:
+ return MODE_ASK;
+ default:
+ return MODE_IGNORED;
+ }
+ }
+
+ private int positionToMode(int position) {
+ switch (position) {
+ case MODE_ALLOWED:
+ return AppOpsManager.MODE_ALLOWED;
+ case MODE_IGNORED:
+ return AppOpsManager.MODE_IGNORED;
+ case MODE_ASK:
+ return AppOpsManager.MODE_ASK;
+ default:
+ return AppOpsManager.MODE_IGNORED;
+ }
+ }
+
+ private static HashMap<Integer, Integer> OP_ICONS = new HashMap<>();
+
+ static {
+ OP_ICONS.put(AppOpsManager.OP_ACTIVATE_VPN, R.drawable.ic_perm_vpn);
+ OP_ICONS.put(AppOpsManager.OP_AUDIO_ALARM_VOLUME, R.drawable.ic_perm_alarm);
+ OP_ICONS.put(AppOpsManager.OP_AUDIO_MEDIA_VOLUME, R.drawable.ic_perm_audio);
+ OP_ICONS.put(AppOpsManager.OP_BLUETOOTH_CHANGE, R.drawable.ic_perm_bluetooth);
+ OP_ICONS.put(AppOpsManager.OP_BOOT_COMPLETED, R.drawable.ic_perm_boot);
+ OP_ICONS.put(AppOpsManager.OP_CHANGE_WIFI_STATE, R.drawable.ic_perm_wifi);
+ OP_ICONS.put(AppOpsManager.OP_DATA_CONNECT_CHANGE, R.drawable.ic_perm_data);
+ OP_ICONS.put(AppOpsManager.OP_GET_USAGE_STATS, R.drawable.ic_perm_data);
+ OP_ICONS.put(AppOpsManager.OP_GPS, R.drawable.ic_perm_location);
+ OP_ICONS.put(AppOpsManager.OP_MUTE_MICROPHONE, R.drawable.ic_perm_microphone);
+ OP_ICONS.put(AppOpsManager.OP_NFC_CHANGE, R.drawable.ic_perm_nfc);
+ OP_ICONS.put(AppOpsManager.OP_POST_NOTIFICATION, R.drawable.ic_perm_notifications);
+ OP_ICONS.put(AppOpsManager.OP_READ_CLIPBOARD, R.drawable.ic_perm_clipboard);
+ OP_ICONS.put(AppOpsManager.OP_RUN_IN_BACKGROUND, R.drawable.ic_perm_background);
+ OP_ICONS.put(AppOpsManager.OP_SU, R.drawable.ic_perm_su);
+ OP_ICONS.put(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, R.drawable.ic_perm_drawontop);
+ OP_ICONS.put(AppOpsManager.OP_TAKE_AUDIO_FOCUS, R.drawable.ic_perm_audio);
+ OP_ICONS.put(AppOpsManager.OP_TOAST_WINDOW, R.drawable.ic_perm_notifications);
+ OP_ICONS.put(AppOpsManager.OP_TURN_SCREEN_ON, R.drawable.ic_perm_turnscreenon);
+ OP_ICONS.put(AppOpsManager.OP_VIBRATE, R.drawable.ic_perm_vibrate);
+ OP_ICONS.put(AppOpsManager.OP_WAKE_LOCK, R.drawable.ic_perm_nosleep);
+ OP_ICONS.put(AppOpsManager.OP_WIFI_SCAN, R.drawable.ic_perm_wifi);
+ OP_ICONS.put(AppOpsManager.OP_WRITE_CLIPBOARD, R.drawable.ic_perm_clipboard);
+ OP_ICONS.put(AppOpsManager.OP_WRITE_SETTINGS, R.drawable.ic_perm_settings);
+ OP_ICONS.put(AppOpsManager.OP_WRITE_SMS , R.drawable.ic_perm_sms);
+ }
+
+ private boolean isPlatformSigned() {
+ final int match = mPm.checkSignatures("android", mPackageInfo.packageName);
+ return match >= PackageManager.SIGNATURE_MATCH;
+ }
+
+ // Utility method to set application label and icon.
+ private void setAppHeader(PackageInfo pkgInfo) {
+ ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ String appLabel = mPm.getApplicationLabel(appInfo).toString();
+ String label;
+ try {
+ label = appInfo.loadLabel(mPm).toString();
+ } catch (Throwable t) {
+ Log.e(TAG, "Error loading application label for " + appLabel, t);
+ label = appLabel;
+ }
+
+ final Activity activity = getActivity();
+ final Preference pref = EntityHeaderController
+ .newInstance(getActivity(), this /* fragment */, null /* header */)
+ .setIcon(mPm.getApplicationIcon(appInfo))
+ .setLabel(label)
+ .setPackageName(appInfo.packageName)
+ .setUid(appInfo.uid)
+ .setHasAppInfoLink(true)
+ .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
+ EntityHeaderController.ActionType.ACTION_NONE)
+ .done(getActivity(), getPrefContext());
+ pref.setKey(KEY_HEADER);
+ getPreferenceScreen().addPreference(pref);
+ }
+
+ private String retrieveAppEntry() {
+ final Bundle args = getArguments();
+ String packageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
+ if (packageName == null) {
+ Intent intent = (args == null) ?
+ getActivity().getIntent() : (Intent) args.getParcelable("intent");
+ if (intent != null) {
+ packageName = intent.getData().getSchemeSpecificPart();
+ }
+ }
+ try {
+ mPackageInfo = mPm.getPackageInfo(packageName,
+ PackageManager.MATCH_DISABLED_COMPONENTS |
+ PackageManager.MATCH_ANY_USER);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package:" + packageName, e);
+ mPackageInfo = null;
+ }
+
+ return packageName;
+ }
+
+ private boolean refreshUi() {
+ if (mPackageInfo == null) {
+ return false;
+ }
+
+ mPreferenceScreen.removeAll();
+ setAppHeader(mPackageInfo);
+
+ AppOpsState.OpsTemplate[] allTemplates = getTemplates();
+ for (AppOpsState.OpsTemplate tpl : allTemplates) {
+ List<AppOpsState.AppOpEntry> entries = mState.buildState(tpl,
+ mPackageInfo.applicationInfo.uid, mPackageInfo.packageName, true);
+ for (final AppOpsState.AppOpEntry entry : entries) {
+ String perm = null;
+ int op = -1;
+ // Find the first permission with a known name
+ for (int i = 0; i < entry.getNumOpEntry() && perm == null; i++) {
+ op = entry.getOpEntry(i).getOp();
+ perm = AppOpsManager.opToPermission(op);
+ }
+ Drawable icon = getIconByPermission(perm);
+ if (icon == null && op != -1 && OP_ICONS.containsKey(op)) {
+ icon = getActivity().getDrawable(OP_ICONS.get(op));
+ }
+ if (icon == null) {
+ Log.e(TAG, "Failed to retrieve icon for permission: " + perm);
+ } else {
+ icon.setTint(Utils.getColorAttr(getActivity(),
+ android.R.attr.colorControlNormal));
+ }
+
+ final AppOpsManager.OpEntry firstOp = entry.getOpEntry(0);
+ final int switchOp = AppOpsManager.opToSwitch(firstOp.getOp());
+
+ // ListPreference for 3 states: ask, allow, deny
+ if (AppOpsManager.isStrictOp(switchOp)) {
+ ListPreference listPref = getListPrefForEntry(entry, icon);
+ mPreferenceScreen.addPreference(listPref);
+ } else {
+ SwitchPreference switchPref = getSwitchPrefForEntry(entry, icon);
+ mPreferenceScreen.addPreference(switchPref);
+ }
+ }
+ }
+
+ if (mPreferenceScreen.getPreferenceCount() == 0) {
+ Preference noBlockablePermissionsPref = getNoBlockablePermissionsPref();
+ mPreferenceScreen.addPreference(noBlockablePermissionsPref);
+ }
+
+ return true;
+ }
+
+ private AppOpsState.OpsTemplate[] getTemplates() {
+ /* If we are platform signed, only show the root switch, this
+ * one is safe to toggle while other permission-based ones could
+ * certainly cause system-wide problems
+ */
+ if (isPlatformSigned()) {
+ return new AppOpsState.OpsTemplate[]{ AppOpsState.SU_TEMPLATE };
+ }
+
+ int length = AppOpsState.ALL_PERMS_TEMPLATES.length;
+ AppOpsState.OpsTemplate[] allTemplates = new AppOpsState.OpsTemplate[length];
+ // Loop all existing templates and set the visibility of each perm to true
+ for (int i = 0; i < length; i++) {
+ AppOpsState.OpsTemplate tpl = AppOpsState.ALL_PERMS_TEMPLATES[i];
+ for (int j = 0; j < tpl.ops.length; j++) {
+ // we only want to use the template's orderings, not the visibility
+ tpl.showPerms[j] = true;
+ }
+
+ allTemplates[i] = tpl;
+ }
+
+ return allTemplates;
+ }
+
+ private Drawable getIconByPermission(String perm) {
+ Drawable icon = null;
+ if (perm != null) {
+ try {
+ PermissionInfo pi = mPm.getPermissionInfo(perm, 0);
+ if (pi.group != null) {
+ PermissionGroupInfo pgi = mPm.getPermissionGroupInfo(pi.group, 0);
+ if (pgi.icon != 0) {
+ icon = pgi.loadIcon(mPm);
+ }
+ }
+ } catch (NameNotFoundException e) {
+ }
+ }
+ return icon;
+ }
+
+ private ListPreference getListPrefForEntry(final AppOpsState.AppOpEntry entry, Drawable icon) {
+ final Resources res = getActivity().getResources();
+
+ final AppOpsManager.OpEntry firstOp = entry.getOpEntry(0);
+ final AppOpsManager.PackageOps pkgOps = entry.getPackageOps();
+ final int uid = pkgOps.getUid();
+ final String pkgName = pkgOps.getPackageName();
+ final int switchOp = AppOpsManager.opToSwitch(firstOp.getOp());
+ final int mode = mAppOps.checkOpNoThrow(switchOp, uid, pkgName);
+ final CharSequence opName = entry.getSwitchText(mState);
+
+ ListPreference listPref = new ListPreference(getActivity());
+ listPref.setLayoutResource(R.layout.preference_appops);
+ listPref.setIcon(icon);
+ listPref.setTitle(opName);
+ listPref.setDialogTitle(opName);
+ listPref.setEntries(R.array.app_ops_permissions);
+ listPref.setEntryValues(MODE_ENTRIES);
+ listPref.setValueIndex(modeToPosition(mode));
+ String summary = getSummary(listPref.getEntry(), entry.getCountsText(res),
+ entry.getTimeText(res, true));
+ listPref.setSummary(summary);
+ listPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ ListPreference listPref = (ListPreference) preference;
+ String value = newValue.toString();
+ int selectedIndex = listPref.findIndexOfValue(value);
+ mAppOps.setMode(switchOp, uid, pkgName, positionToMode(selectedIndex));
+ String summary = getSummary(listPref.getEntries()[selectedIndex],
+ entry.getCountsText(res), entry.getTimeText(res, true));
+ listPref.setSummary(summary);
+ return true;
+ }
+ });
+
+ return listPref;
+ }
+
+ private SwitchPreference getSwitchPrefForEntry(final AppOpsState.AppOpEntry entry,
+ Drawable icon) {
+ final Resources res = getActivity().getResources();
+
+ final AppOpsManager.OpEntry firstOp = entry.getOpEntry(0);
+ final AppOpsManager.PackageOps pkgOps = entry.getPackageOps();
+ final int uid = pkgOps.getUid();
+ final String pkgName = pkgOps.getPackageName();
+ final int switchOp = AppOpsManager.opToSwitch(firstOp.getOp());
+ final int mode = mAppOps.checkOpNoThrow(switchOp, uid, pkgName);
+ final CharSequence opName = entry.getSwitchText(mState);
+
+ SwitchPreference switchPref = new SwitchPreference(getActivity());
+ switchPref.setLayoutResource(R.layout.preference_appops);
+ switchPref.setIcon(icon);
+ switchPref.setTitle(opName);
+ String summary = getSummary(entry.getCountsText(res), entry.getTimeText(res, true));
+ switchPref.setSummary(summary);
+ switchPref.setChecked(mode == AppOpsManager.MODE_ALLOWED);
+ switchPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference,
+ Object newValue) {
+ Boolean isChecked = (Boolean) newValue;
+ mAppOps.setMode(switchOp, uid, pkgName,
+ isChecked ? AppOpsManager.MODE_ALLOWED
+ : AppOpsManager.MODE_IGNORED);
+ return true;
+ }
+ });
+
+ return switchPref;
+ }
+
+ private Preference getNoBlockablePermissionsPref() {
+ Preference emptyPref = new Preference(getActivity());
+ emptyPref.setTitle(R.string.app_ops_no_blockable_permissions);
+ emptyPref.setSelectable(false);
+ emptyPref.setEnabled(false);
+ return emptyPref;
+ }
+
+
+ private void setIntentAndFinish(boolean finish, boolean appChanged) {
+ Intent intent = new Intent();
+ intent.putExtra(ManageApplications.APP_CHG, appChanged);
+ SettingsActivity sa = (SettingsActivity)getActivity();
+ sa.finishPreferencePanel(Activity.RESULT_OK, intent);
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mState = new AppOpsState(getActivity());
+ mPm = getActivity().getPackageManager();
+ mAppOps = (AppOpsManager)getActivity().getSystemService(Context.APP_OPS_SERVICE);
+ mPreferenceScreen = getPreferenceManager().createPreferenceScreen(getActivity());
+ retrieveAppEntry();
+
+ setPreferenceScreen(mPreferenceScreen);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.APP_OPS_DETAILS;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ private String getSummary(CharSequence... lines) {
+ StringJoiner sj = new StringJoiner("\n");
+ for (CharSequence line : lines) {
+ if (!TextUtils.isEmpty(line)) {
+ sj.add(line);
+ }
+ }
+ return sj.toString();
+ }
+}
diff --git a/src/com/android/settings/applications/appops/AppOpsDetailsTop.java b/src/com/android/settings/applications/appops/AppOpsDetailsTop.java
new file mode 100644
index 0000000..0353bb3
--- /dev/null
+++ b/src/com/android/settings/applications/appops/AppOpsDetailsTop.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2015 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.applications.appops;
+
+import android.content.Intent;
+import android.preference.PreferenceActivity;
+
+public class AppOpsDetailsTop extends PreferenceActivity {
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, AppOpsDetails.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ if (AppOpsDetails.class.getName().equals(fragmentName)) return true;
+ return false;
+ }
+}
diff --git a/src/com/android/settings/applications/appops/AppOpsState.java b/src/com/android/settings/applications/appops/AppOpsState.java
index 2686b8c..7684c46 100644
--- a/src/com/android/settings/applications/appops/AppOpsState.java
+++ b/src/com/android/settings/applications/appops/AppOpsState.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2018 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,7 @@
package com.android.settings.applications.appops;
+import android.app.Activity;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -23,6 +25,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
+import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,7 +41,9 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class AppOpsState {
static final String TAG = "AppOpsState";
@@ -50,12 +55,17 @@
final CharSequence[] mOpSummaries;
final CharSequence[] mOpLabels;
+ List<AppOpEntry> mApps;
+
+ private SharedPreferences mPreferences;
+
public AppOpsState(Context context) {
mContext = context;
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
mPm = context.getPackageManager();
- mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries);
- mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels);
+ mOpSummaries = context.getResources().getTextArray(R.array.app_ops_summaries_lineage);
+ mOpLabels = context.getResources().getTextArray(R.array.app_ops_labels_lineage);
+ mPreferences = context.getSharedPreferences("appops_manager", Activity.MODE_PRIVATE);
}
public static class OpsTemplate implements Parcelable {
@@ -180,6 +190,7 @@
false,
false,
false,
+ false,
false }
);
@@ -193,7 +204,11 @@
AppOpsManager.OP_PROJECT_MEDIA,
AppOpsManager.OP_ACTIVATE_VPN,
AppOpsManager.OP_ASSIST_STRUCTURE,
- AppOpsManager.OP_ASSIST_SCREENSHOT},
+ AppOpsManager.OP_ASSIST_SCREENSHOT,
+ AppOpsManager.OP_CHANGE_WIFI_STATE,
+ AppOpsManager.OP_BLUETOOTH_CHANGE,
+ AppOpsManager.OP_NFC_CHANGE,
+ AppOpsManager.OP_DATA_CONNECT_CHANGE },
new boolean[] { false,
true,
true,
@@ -203,7 +218,11 @@
false,
false,
false,
- false }
+ false,
+ true,
+ true,
+ true,
+ true }
);
public static final OpsTemplate RUN_IN_BACKGROUND_TEMPLATE = new OpsTemplate(
@@ -211,9 +230,62 @@
new boolean[] { false }
);
+ public static final OpsTemplate BOOTUP_TEMPLATE = new OpsTemplate(
+ new int[] { AppOpsManager.OP_BOOT_COMPLETED },
+ new boolean[] { true }
+ );
+
+ public static final OpsTemplate SU_TEMPLATE = new OpsTemplate(
+ new int[] { AppOpsManager.OP_SU },
+ new boolean[] { false }
+ );
+
+ // this template should contain all ops which are not part of any other template in
+ // ALL_TEMPLATES
+ public static final OpsTemplate REMAINING_TEMPLATE = new OpsTemplate(
+ new int[] { AppOpsManager.OP_GET_USAGE_STATS,
+ AppOpsManager.OP_TOAST_WINDOW,
+ AppOpsManager.OP_WRITE_WALLPAPER,
+ AppOpsManager.OP_READ_PHONE_STATE,
+ AppOpsManager.OP_ADD_VOICEMAIL,
+ AppOpsManager.OP_USE_SIP,
+ AppOpsManager.OP_PROCESS_OUTGOING_CALLS,
+ AppOpsManager.OP_USE_FINGERPRINT,
+ AppOpsManager.OP_BODY_SENSORS,
+ AppOpsManager.OP_READ_CELL_BROADCASTS,
+ AppOpsManager.OP_MOCK_LOCATION,
+ AppOpsManager.OP_READ_EXTERNAL_STORAGE,
+ AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+ AppOpsManager.OP_TURN_SCREEN_ON,
+ AppOpsManager.OP_GET_ACCOUNTS },
+ new boolean[] { true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true }
+ );
+
public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
- MEDIA_TEMPLATE, DEVICE_TEMPLATE, RUN_IN_BACKGROUND_TEMPLATE
+ MEDIA_TEMPLATE, DEVICE_TEMPLATE, RUN_IN_BACKGROUND_TEMPLATE,
+ BOOTUP_TEMPLATE, SU_TEMPLATE
+ };
+
+ // this template contains all permissions grouped by templates
+ public static final OpsTemplate[] ALL_PERMS_TEMPLATES = new OpsTemplate[] {
+ LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
+ MEDIA_TEMPLATE, DEVICE_TEMPLATE, RUN_IN_BACKGROUND_TEMPLATE,
+ BOOTUP_TEMPLATE, SU_TEMPLATE, REMAINING_TEMPLATE
};
/**
@@ -378,30 +450,59 @@
}
private CharSequence getCombinedText(ArrayList<AppOpsManager.OpEntry> ops,
- CharSequence[] items) {
- if (ops.size() == 1) {
- return items[ops.get(0).getOp()];
- } else {
- StringBuilder builder = new StringBuilder();
- for (int i=0; i<ops.size(); i++) {
- if (i > 0) {
- builder.append(", ");
- }
- builder.append(items[ops.get(i).getOp()]);
+ CharSequence[] items, Resources res, boolean withTerseCounts) {
+ StringBuilder builder = new StringBuilder();
+ for (int i=0; i<ops.size(); i++) {
+ if (i > 0) {
+ builder.append(", ");
}
- return builder.toString();
+ AppOpsManager.OpEntry op = ops.get(i);
+ int count = op.getAllowedCount() + op.getIgnoredCount();
+
+ if (withTerseCounts && count > 0) {
+ String quantity = res.getQuantityString(R.plurals.app_ops_count,
+ count, count);
+ builder.append(res.getString(R.string.app_ops_entry_summary,
+ items[op.getOp()], quantity));
+ } else {
+ builder.append(items[op.getOp()]);
+ }
}
+ return builder.toString();
+ }
+
+ public CharSequence getCountsText(Resources res) {
+ AppOpsManager.OpEntry op = mOps.get(0);
+ int allowed = op.getAllowedCount();
+ int denied = op.getIgnoredCount();
+
+ if (allowed == 0 && denied == 0) {
+ return null;
+ }
+
+ CharSequence allowedQuantity = res.getQuantityString(R.plurals.app_ops_count,
+ allowed, allowed);
+ CharSequence deniedQuantity = res.getQuantityString(R.plurals.app_ops_count,
+ denied, denied);
+
+ if (denied == 0) {
+ return res.getString(R.string.app_ops_allowed_count, allowedQuantity);
+ } else if (allowed == 0) {
+ return res.getString(R.string.app_ops_ignored_count, deniedQuantity);
+ }
+ return res.getString(R.string.app_ops_both_count, allowedQuantity, deniedQuantity);
}
public CharSequence getSummaryText(AppOpsState state) {
- return getCombinedText(mOps, state.mOpSummaries);
+ return getCombinedText(mOps, state.mOpSummaries, state.mContext.getResources(), true);
}
public CharSequence getSwitchText(AppOpsState state) {
+ final Resources res = state.mContext.getResources();
if (mSwitchOps.size() > 0) {
- return getCombinedText(mSwitchOps, state.mOpLabels);
+ return getCombinedText(mSwitchOps, state.mOpLabels, res, false);
} else {
- return getCombinedText(mOps, state.mOpLabels);
+ return getCombinedText(mOps, state.mOpLabels, res, false);
}
}
@@ -501,19 +602,34 @@
}
private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries,
- final String packageName, ApplicationInfo appInfo) {
+ final String packageName, ApplicationInfo appInfo, boolean applyFilters) {
+
+ if (appInfo == null) {
+ try {
+ appInfo = mPm.getApplicationInfo(packageName,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_UNINSTALLED_PACKAGES);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Unable to find info for package " + packageName);
+ return null;
+ }
+ }
+
+ if (applyFilters) {
+ // Hide user apps if needed
+ if (!shouldShowUserApps() &&
+ (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ return null;
+ }
+ // Hide system apps if needed
+ if (!shouldShowSystemApps() &&
+ (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return null;
+ }
+ }
+
AppEntry appEntry = appEntries.get(packageName);
if (appEntry == null) {
- if (appInfo == null) {
- try {
- appInfo = mPm.getApplicationInfo(packageName,
- PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_ANY_USER);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Unable to find info for package " + packageName);
- return null;
- }
- }
appEntry = new AppEntry(this, appInfo);
appEntry.loadLabel(context);
appEntries.put(packageName, appEntry);
@@ -521,12 +637,35 @@
return appEntry;
}
- public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) {
- return buildState(tpl, uid, packageName, RECENCY_COMPARATOR);
+ private boolean shouldShowUserApps() {
+ return mPreferences.getBoolean("show_user_apps", true);
+ }
+
+ private boolean shouldShowSystemApps() {
+ return mPreferences.getBoolean("show_system_apps", true);
+ }
+
+ public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName,
+ boolean privacyGuard) {
+ return buildState(tpl, uid, packageName, RECENCY_COMPARATOR, privacyGuard);
}
public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName,
Comparator<AppOpEntry> comparator) {
+ return buildState(tpl, uid, packageName, comparator, false);
+ }
+
+ private boolean isPrivacyGuardOp(int op) {
+ for (int privacyGuardOp : AppOpsManager.PRIVACY_GUARD_OP_STATES) {
+ if (privacyGuardOp == op) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName,
+ Comparator<AppOpEntry> comparator, boolean privacyGuard) {
final Context context = mContext;
final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>();
@@ -535,7 +674,25 @@
final ArrayList<String> perms = new ArrayList<String>();
final ArrayList<Integer> permOps = new ArrayList<Integer>();
final int[] opToOrder = new int[AppOpsManager._NUM_OP];
+
+ final Set<Integer> privacyGuardOps = new HashSet<>();
+
for (int i=0; i<tpl.ops.length; i++) {
+ if (privacyGuard && isPrivacyGuardOp(tpl.ops[i])) {
+ // If there's a permission for this Privacy Guard OP, then
+ // we don't have to treat it in a special way. The application
+ // should have the permission declared if it uses it, so we
+ // will add this later when we query PackageManager
+ String perm = AppOpsManager.opToPermission(tpl.ops[i]);
+ if (perm != null) {
+ if (DEBUG) Log.d(TAG, "Adding " + AppOpsManager.opToName(tpl.ops[i])
+ + " (" + tpl.ops[i] + ") to privacyGuardOps");
+ privacyGuardOps.add(tpl.ops[i]);
+ } else {
+ if (DEBUG) Log.d(TAG, "Not adding " + AppOpsManager.opToName(tpl.ops[i])
+ + " (" + tpl.ops[i] + ") with perm " + perm + " to privacyGuardOps");
+ }
+ }
if (tpl.showPerms[i]) {
String perm = AppOpsManager.opToPermission(tpl.ops[i]);
if (perm != null && !perms.contains(perm)) {
@@ -546,6 +703,9 @@
}
}
+ // Whether to apply hide user / system app filters
+ final boolean applyFilters = (packageName == null);
+
List<AppOpsManager.PackageOps> pkgs;
if (packageName != null) {
pkgs = mAppOps.getOpsForPackage(uid, packageName, tpl.ops);
@@ -556,12 +716,21 @@
if (pkgs != null) {
for (int i=0; i<pkgs.size(); i++) {
AppOpsManager.PackageOps pkgOps = pkgs.get(i);
- AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null);
+ AppEntry appEntry = getAppEntry(context, appEntries, pkgOps.getPackageName(), null,
+ applyFilters);
if (appEntry == null) {
continue;
}
for (int j=0; j<pkgOps.getOps().size(); j++) {
AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j);
+ if (privacyGuard && privacyGuardOps.contains(opEntry.getOp())) {
+ // This OP is here because the user enabled Privacy Guard
+ // for this application.
+ if (DEBUG) Log.d(TAG, "Not adding "
+ + AppOpsManager.opToName(opEntry.getOp())
+ + " (" + opEntry.getOp() + ")");
+ continue;
+ }
addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
packageName == null ? 0 : opToOrder[opEntry.getOp()]);
}
@@ -584,7 +753,7 @@
for (int i=0; i<apps.size(); i++) {
PackageInfo appInfo = apps.get(i);
AppEntry appEntry = getAppEntry(context, appEntries, appInfo.packageName,
- appInfo.applicationInfo);
+ appInfo.applicationInfo, applyFilters);
if (appEntry == null) {
continue;
}
@@ -593,7 +762,7 @@
if (appInfo.requestedPermissions != null) {
for (int j=0; j<appInfo.requestedPermissions.length; j++) {
if (appInfo.requestedPermissionsFlags != null) {
- if ((appInfo.requestedPermissionsFlags[j]
+ if (!privacyGuard && (appInfo.requestedPermissionsFlags[j]
& PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
if (DEBUG) Log.d(TAG, "Pkg " + appInfo.packageName + " perm "
+ appInfo.requestedPermissions[j] + " not granted; skipping");
@@ -618,7 +787,7 @@
}
AppOpsManager.OpEntry opEntry = new AppOpsManager.OpEntry(
- permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0, -1, null);
+ permOps.get(k), AppOpsManager.MODE_ALLOWED, 0, 0, 0, -1, null, 0, 0);
dummyOps.add(opEntry);
addOp(entries, pkgOps, appEntry, opEntry, packageName == null,
packageName == null ? 0 : opToOrder[opEntry.getOp()]);
diff --git a/src/com/android/settings/applications/appops/AppOpsSummary.java b/src/com/android/settings/applications/appops/AppOpsSummary.java
new file mode 100644
index 0000000..be1e9d6
--- /dev/null
+++ b/src/com/android/settings/applications/appops/AppOpsSummary.java
@@ -0,0 +1,272 @@
+/**
+ * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.applications.appops;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AppOpsManager;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceFrameLayout;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.PagerTabStrip;
+import android.support.v4.view.ViewPager;
+import android.util.Pair;
+import android.util.TypedValue;
+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 com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.android.settings.development.RootAccessPreferenceController;
+import com.android.settings.R;
+
+public class AppOpsSummary extends InstrumentedPreferenceFragment {
+ // layout inflater object used to inflate views
+ private LayoutInflater mInflater;
+
+ private ViewGroup mContentContainer;
+ private View mRootView;
+ private ViewPager mViewPager;
+
+ private MyPagerAdapter mAdapter;
+
+ private Activity mActivity;
+ private SharedPreferences mPreferences;
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.APP_OPS_SUMMARY;
+ }
+
+ static class MyPagerAdapter extends FragmentPagerAdapter
+ implements ViewPager.OnPageChangeListener {
+ private List<Pair<CharSequence, AppOpsState.OpsTemplate>> mPageData;
+ private int mCurPos;
+
+ public MyPagerAdapter(FragmentManager fm,
+ List<Pair<CharSequence, AppOpsState.OpsTemplate>> data) {
+ super(fm);
+ mPageData = data;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return new AppOpsCategory(mPageData.get(position).second);
+ }
+
+ @Override
+ public int getCount() {
+ return mPageData.size();
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return mPageData.get(position).first;
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ mCurPos = position;
+ }
+
+ public int getCurrentPage() {
+ return mCurPos;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_IDLE) {
+ //updateCurrentTab(mCurPos);
+ }
+ }
+ }
+
+ private void resetAdapter() {
+ // trigger adapter load, preserving the selected page
+ int curPos = mAdapter.getCurrentPage();
+ mViewPager.setAdapter(mAdapter);
+ mViewPager.setOnPageChangeListener(mAdapter);
+ mViewPager.setCurrentItem(curPos);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // initialize the inflater
+ mInflater = inflater;
+
+ View rootView = mInflater.inflate(R.layout.app_ops_summary,
+ container, false);
+ mContentContainer = container;
+ mRootView = rootView;
+
+ CharSequence[] pageNames = getResources().getTextArray(R.array.app_ops_categories_lineage);
+ AppOpsState.OpsTemplate[] templates = AppOpsState.ALL_PERMS_TEMPLATES;
+ assert(pageNames.length == templates.length);
+
+ int specificTab = -1;
+ Bundle bundle = getArguments();
+ if (bundle != null) {
+ specificTab = Arrays.asList(pageNames).indexOf(bundle.getString("appops_tab", ""));
+ }
+
+ List<Pair<CharSequence, AppOpsState.OpsTemplate>> pageData = new ArrayList<>();
+ for (int i = 0; i < pageNames.length; i++) {
+ pageData.add(Pair.create(pageNames[i], templates[i]));
+ }
+ filterPageData(pageData, specificTab);
+
+ mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
+ mAdapter = new MyPagerAdapter(getChildFragmentManager(), pageData);
+ mViewPager.setAdapter(mAdapter);
+ mViewPager.setOnPageChangeListener(mAdapter);
+ PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
+
+ // HACK - https://code.google.com/p/android/issues/detail?id=213359
+ ((ViewPager.LayoutParams) tabs.getLayoutParams()).isDecor = true;
+
+ Resources.Theme theme = tabs.getContext().getTheme();
+ TypedValue typedValue = new TypedValue();
+ theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+ final int colorAccent = getContext().getColor(typedValue.resourceId);
+ tabs.setTabIndicatorColor(colorAccent);
+
+ // We have to do this now because PreferenceFrameLayout looks at it
+ // only when the view is added.
+ if (container instanceof PreferenceFrameLayout) {
+ ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
+ }
+
+ mActivity = getActivity();
+
+ return rootView;
+ }
+
+ private void filterPageData(List<Pair<CharSequence, AppOpsState.OpsTemplate>> data, int tab) {
+ if (tab >= 0 && tab < data.size()) {
+ Pair<CharSequence, AppOpsState.OpsTemplate> item = data.get(tab);
+ data.clear();
+ data.add(item);
+ } else if (!RootAccessPreferenceController.isRootForAppsEnabled()) {
+ for (Pair<CharSequence, AppOpsState.OpsTemplate> item : data) {
+ if (item.second == AppOpsState.SU_TEMPLATE) {
+ data.remove(item);
+ return;
+ }
+ }
+ }
+ }
+
+ private boolean shouldShowUserApps() {
+ return mPreferences.getBoolean("show_user_apps", true);
+ }
+
+ private boolean shouldShowSystemApps() {
+ return mPreferences.getBoolean("show_system_apps", true);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ // get shared preferences
+ mPreferences = mActivity.getSharedPreferences("appops_manager", Activity.MODE_PRIVATE);
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.appops_manager, menu);
+ menu.findItem(R.id.show_user_apps).setChecked(shouldShowUserApps());
+ menu.findItem(R.id.show_system_apps).setChecked(shouldShowSystemApps());
+ }
+
+ private void resetCounters() {
+ final AppOpsManager appOps =
+ (AppOpsManager) mActivity.getSystemService(Context.APP_OPS_SERVICE);
+ if (appOps == null) {
+ return;
+ }
+ appOps.resetCounters();
+ // reload content
+ resetAdapter();
+ }
+
+ private void resetCountersConfirm() {
+ new AlertDialog.Builder(getActivity())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(R.string.app_ops_reset_confirm_title)
+ .setMessage(R.string.app_ops_reset_confirm_mesg)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ resetCounters();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.show_user_apps:
+ final String prefNameUserApps = "show_user_apps";
+ // set the menu checkbox and save it in shared preference
+ item.setChecked(!item.isChecked());
+ mPreferences.edit().putBoolean(prefNameUserApps, item.isChecked()).commit();
+ // reload content
+ resetAdapter();
+ return true;
+ case R.id.show_system_apps:
+ final String prefNameSysApps = "show_system_apps";
+ // set the menu checkbox and save it in shared preference
+ item.setChecked(!item.isChecked());
+ mPreferences.edit().putBoolean(prefNameSysApps, item.isChecked()).commit();
+ // reload view content
+ resetAdapter();
+ return true;
+ case R.id.reset_counters:
+ resetCountersConfirm();
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbBackend.java b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
index 54811c8..9b0dcec 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbBackend.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
@@ -153,6 +153,30 @@
.isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
}
+ public boolean isSingleDataRoleSupported() {
+ return mPort != null && mPortStatus != null
+ && ((!mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST)
+ && !mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST))
+ || (!mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE)
+ && !mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE)));
+ }
+
+ public boolean isSinglePowerRoleSupported() {
+ return mPort != null && mPortStatus != null
+ && ((!mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE)
+ && !mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST))
+ || (!mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE)
+ && !mPortStatus
+ .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST)));
+ }
+
public static String usbFunctionsToString(long functions) {
// TODO replace with UsbManager.usbFunctionsToString once supported by Roboelectric
return Long.toBinaryString(functions);
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
index 93ff19e..6474419 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
@@ -109,7 +109,8 @@
@Override
public boolean isAvailable() {
- return !Utils.isMonkeyRunning();
+ return !Utils.isMonkeyRunning()
+ && !mUsbBackend.isSingleDataRoleSupported();
}
@Override
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
index 77a7eb4..ae57129 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
@@ -118,7 +118,8 @@
@Override
public boolean isAvailable() {
- return !Utils.isMonkeyRunning();
+ return !Utils.isMonkeyRunning()
+ && !mUsbBackend.isSinglePowerRoleSupported();
}
@Override
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 20a80d1..75acb64 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -57,7 +57,8 @@
public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
implements SwitchBar.OnSwitchChangeListener, OemUnlockDialogHost, AdbDialogHost,
AdbClearKeysDialogHost, LogPersistDialogHost,
- BluetoothA2dpHwOffloadRebootDialog.OnA2dpHwDialogConfirmedListener {
+ BluetoothA2dpHwOffloadRebootDialog.OnA2dpHwDialogConfirmedListener,
+ RootAccessDialogHost {
private static final String TAG = "DevSettingsDashboard";
@@ -278,6 +279,20 @@
}
@Override
+ public void onRootAccessDialogConfirmed() {
+ final RootAccessPreferenceController controller =
+ getDevelopmentOptionsController(RootAccessPreferenceController.class);
+ controller.onRootAccessDialogConfirmed();
+ }
+
+ @Override
+ public void onRootAccessDialogDismissed() {
+ final RootAccessPreferenceController controller =
+ getDevelopmentOptionsController(RootAccessPreferenceController.class);
+ controller.onRootAccessDialogDismissed();
+ }
+
+ @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
boolean handledResult = false;
for (AbstractPreferenceController controller : mPreferenceControllers) {
@@ -455,6 +470,8 @@
controllers.add(new FreeformWindowsPreferenceController(context));
controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
+ controllers.add(new RootAccessPreferenceController(context, fragment));
+ controllers.add(new RootAppOpsPreferenceController(context));
controllers.add(new DefaultLaunchPreferenceController(context, "running_apps"));
controllers.add(new DefaultLaunchPreferenceController(context, "demo_mode"));
controllers.add(new DefaultLaunchPreferenceController(context, "quick_settings_tiles"));
diff --git a/src/com/android/settings/development/RootAccessDialogHost.java b/src/com/android/settings/development/RootAccessDialogHost.java
new file mode 100644
index 0000000..4a31ae8
--- /dev/null
+++ b/src/com/android/settings/development/RootAccessDialogHost.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.development;
+
+/**
+ * Interface for RootAccessWarningDialogFragment callbacks.
+ */
+public interface RootAccessDialogHost {
+
+ /**
+ * Called when the user presses ok on the warning dialog.
+ */
+ void onRootAccessDialogConfirmed();
+
+ /**
+ * Called when the user dismisses or cancels the warning dialog.
+ */
+ void onRootAccessDialogDismissed();
+}
diff --git a/src/com/android/settings/development/RootAccessPreferenceController.java b/src/com/android/settings/development/RootAccessPreferenceController.java
new file mode 100644
index 0000000..84e53d8
--- /dev/null
+++ b/src/com/android/settings/development/RootAccessPreferenceController.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.development;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+import java.io.File;
+
+public class RootAccessPreferenceController extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String TAG = "RootAccessPreferenceController";
+ private static final String PREF_KEY = "root_access";
+
+ private static final String ROOT_ACCESS_PROPERTY = "persist.sys.root_access";
+
+ private final DevelopmentSettingsDashboardFragment mFragment;
+ private Object mPendingRootAccessValue;
+
+ public RootAccessPreferenceController(Context context,
+ DevelopmentSettingsDashboardFragment fragment) {
+ super(context);
+
+ mFragment = fragment;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ // User builds don't get root, and eng always gets root
+ return Build.IS_DEBUGGABLE || "eng".equals(Build.TYPE);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREF_KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ File file = new File("/system/xbin/su");
+
+ if (file.exists()) {
+ ((ListPreference) mPreference).setEntries(R.array.root_access_entries);
+ ((ListPreference) mPreference).setEntryValues(R.array.root_access_values);
+ } else {
+ ((ListPreference) mPreference).setEntries(R.array.root_access_entries_adb);
+ ((ListPreference) mPreference).setEntryValues(R.array.root_access_values_adb);
+ }
+
+ updatePreference();
+
+ if (!isAdminUser()) {
+ mPreference.setEnabled(false);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if ("0".equals(newValue.toString())) {
+ writeRootAccessOptions(newValue);
+ } else {
+ mPendingRootAccessValue = newValue;
+ RootAccessWarningDialog.show(mFragment);
+ }
+ return true;
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ if (isAdminUser()) {
+ mPreference.setEnabled(true);
+ }
+ }
+
+ public void onRootAccessDialogConfirmed() {
+ writeRootAccessOptions(mPendingRootAccessValue);
+ }
+
+ public void onRootAccessDialogDismissed() {
+ updatePreference();
+ }
+
+ public static boolean isRootForAppsEnabled() {
+ int value = SystemProperties.getInt(ROOT_ACCESS_PROPERTY, 0);
+ boolean daemonState =
+ SystemProperties.get("init.svc.su_daemon", "absent").equals("running");
+ return daemonState && (value == 1 || value == 3);
+ }
+
+ private void writeRootAccessOptions(Object newValue) {
+ String oldValue = SystemProperties.get(ROOT_ACCESS_PROPERTY, "0");
+ SystemProperties.set(ROOT_ACCESS_PROPERTY, newValue.toString());
+ if (Integer.valueOf(newValue.toString()) < 2 && !oldValue.equals(newValue)
+ && SystemProperties.getInt("service.adb.root", 0) == 1) {
+ SystemProperties.set("service.adb.root", "0");
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 0);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ADB_ENABLED, 1);
+ }
+ updatePreference();
+ }
+
+ private void updatePreference() {
+ String value = SystemProperties.get(ROOT_ACCESS_PROPERTY, "0");
+ ((ListPreference) mPreference).setValue(value);
+ ((ListPreference) mPreference).setSummary(mContext.getResources()
+ .getStringArray(R.array.root_access_entries)[Integer.valueOf(value)]);
+ }
+
+ @VisibleForTesting
+ boolean isAdminUser() {
+ return ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).isAdminUser();
+ }
+}
diff --git a/src/com/android/settings/development/RootAccessWarningDialog.java b/src/com/android/settings/development/RootAccessWarningDialog.java
new file mode 100644
index 0000000..a102c98
--- /dev/null
+++ b/src/com/android/settings/development/RootAccessWarningDialog.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.development;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class RootAccessWarningDialog extends InstrumentedDialogFragment implements
+ DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+
+ public static final String TAG = "RootAccessWarningDialog";
+
+ public static void show(Fragment host) {
+ final FragmentManager manager = host.getActivity().getFragmentManager();
+ if (manager.findFragmentByTag(TAG) == null) {
+ final RootAccessWarningDialog dialog =
+ new RootAccessWarningDialog();
+ dialog.setTargetFragment(host, 0 /* requestCode */);
+ dialog.show(manager, TAG);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.TYPE_UNKNOWN;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.root_access_warning_title)
+ .setMessage(R.string.root_access_warning_message)
+ .setPositiveButton(android.R.string.ok, this /* onClickListener */)
+ .setNegativeButton(android.R.string.cancel, this /* onClickListener */)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final RootAccessDialogHost host = (RootAccessDialogHost) getTargetFragment();
+ if (host == null) {
+ return;
+ }
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ host.onRootAccessDialogConfirmed();
+ } else {
+ host.onRootAccessDialogDismissed();
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ final RootAccessDialogHost host = (RootAccessDialogHost) getTargetFragment();
+ if (host == null) {
+ return;
+ }
+ host.onRootAccessDialogDismissed();
+ }
+}
diff --git a/src/com/android/settings/development/RootAppOpsPreferenceController.java b/src/com/android/settings/development/RootAppOpsPreferenceController.java
new file mode 100644
index 0000000..7a6b0f1
--- /dev/null
+++ b/src/com/android/settings/development/RootAppOpsPreferenceController.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The LineageOS 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.development;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.Settings.AppOpsSummaryActivity;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
+
+public class RootAppOpsPreferenceController extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceClickListener, PreferenceControllerMixin {
+
+ private static final String TAG = "RootAppOpsPreferenceController";
+ private static final String PREF_KEY = "root_appops";
+
+ public RootAppOpsPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ // User builds don't get root, and eng always gets root
+ return Build.IS_DEBUGGABLE || "eng".equals(Build.TYPE);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREF_KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreference.setOnPreferenceClickListener(this);
+
+ if (!RootAccessPreferenceController.isRootForAppsEnabled() || !isAdminUser()) {
+ mPreference.setEnabled(false);
+ }
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ if (isAdminUser()) {
+ mPreference.setEnabled(true);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ Bundle args = new Bundle();
+ args.putString("appops_tab",
+ mContext.getResources().getString(R.string.app_ops_categories_su));
+ intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
+ intent.setClass(mContext, AppOpsSummaryActivity.class);
+ mContext.startActivity(intent);
+ return true;
+ }
+
+ @VisibleForTesting
+ boolean isAdminUser() {
+ return ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).isAdminUser();
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java b/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
index 6169b44..c6d399b 100644
--- a/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 Fairphone B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +24,7 @@
import android.os.SystemProperties;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@@ -31,10 +33,33 @@
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.fairphone.common.modules.BatteryModule;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class HardwareInfoDialogFragment extends InstrumentedDialogFragment {
public static final String TAG = "HardwareInfo";
+ private static final String ASSEMBLY_NUMBER_FILE = "/persist/phoneid.bin";
+ private static final String FILENAME_PROC_CPUINFO = "/proc/cpuinfo";
+ private static final String KEY_RECEIVER_MODULE_INFO = "receiver_module_info";
+ private static final String PROPERTY_FRONT_CAMERA_SENSOR = "fp2.cam.front.sensor";
+ private static final String VALUE_FRONT_CAMERA_SENSOR_OV2685 = "ov2685";
+ private static final String VALUE_FRONT_CAMERA_SENSOR_OV5670 = "ov5670";
+ private static final String KEY_CAMERA_MODULE_INFO = "camera_module_info";
+ private static final String PROPERTY_MAIN_CAMERA_SENSOR = "fp2.cam.main.sensor";
+ private static final String VALUE_MAIN_CAMERA_SENSOR_OV8865 = "ov8865_q8v18a";
+ private static final String VALUE_MAIN_CAMERA_SENSOR_OV12870 = "ov12870";
+ private static final String KEY_BATTERY_MODULE_INFO = "battery_module_info";
+
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DIALOG_SETTINGS_HARDWARE_INFO;
@@ -63,6 +88,24 @@
setText(content, R.id.hardware_rev_label, R.id.hardware_rev_value,
SystemProperties.get("ro.boot.hardware.revision"));
+ // Assembly number
+ setText(content, R.id.assembly_number_label, R.id.assembly_number_value,
+ getAssemblyNumber());
+
+ // Processor
+ setText(content, R.id.processor_label, R.id.processor_value, getProcessorInfo());
+
+ // Receiver module
+ setText(content, R.id.receiver_module_label, R.id.receiver_module_value,
+ getReceiverModuleInfo());
+
+ // Camera module
+ setText(content, R.id.camera_module_label, R.id.camera_module_value, getCameraModuleInfo());
+
+ // Battery module
+ setText(content, R.id.battery_module_label, R.id.battery_module_value,
+ getBatteryModuleInfo());
+
return builder.setView(content).create();
}
@@ -87,4 +130,118 @@
String getSerialNumber() {
return Build.getSerial();
}
+
+ private static String getAssemblyNumber() {
+ String assemblyNumber = null;
+ FileInputStream input = null;
+
+ try {
+ input = new FileInputStream(new File(ASSEMBLY_NUMBER_FILE));
+ final byte[] bytes = new byte[input.available()];
+
+ input.read(bytes);
+ assemblyNumber = new String(bytes, "ASCII");
+ } catch (FileNotFoundException e) {
+ Log.wtf(TAG, "Assembly number file not found", e);
+ } catch(IOException e) {
+ Log.wtf(TAG, "Could not read the assembly number file", e);
+ } finally {
+ try {
+ if (input != null) {
+ input.close();
+ }
+ } catch (Exception e) {
+ Log.wtf(TAG, e);
+ }
+ }
+
+ return assemblyNumber;
+ }
+
+ /**
+ * Returns the Hardware value in /proc/cpuinfo, else returns "Unknown".
+ * @return a string that describes the processor
+ */
+ private static String getProcessorInfo() {
+ // Hardware : XYZ
+ final String PROC_HARDWARE_REGEX = "Hardware\\s*:\\s*(.*)$"; /* hardware string */
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(FILENAME_PROC_CPUINFO));
+ String cpuinfo;
+
+ try {
+ while (null != (cpuinfo = reader.readLine())) {
+ if (cpuinfo.startsWith("Hardware")) {
+ Matcher m = Pattern.compile(PROC_HARDWARE_REGEX).matcher(cpuinfo);
+ if (m.matches()) {
+ return m.group(1);
+ }
+ }
+ }
+ return "Unknown";
+ } finally {
+ reader.close();
+ }
+ } catch (IOException e) {
+ Log.e(TAG,
+ "IO Exception when getting cpuinfo for Device Info screen",
+ e);
+
+ return "Unknown";
+ }
+ }
+
+ private String getReceiverModuleInfo() {
+ final String frontCameraSensor = SystemProperties.get(PROPERTY_FRONT_CAMERA_SENSOR);
+ String info;
+
+ if (VALUE_FRONT_CAMERA_SENSOR_OV2685.equals(frontCameraSensor)) {
+ info = getResources().getString(R.string.receiver_module_ov2685);
+ } else if (VALUE_FRONT_CAMERA_SENSOR_OV5670.equals(frontCameraSensor)) {
+ info = getResources().getString(R.string.receiver_module_ov5670);
+ } else {
+ // Unexpected property value, or missing
+ info = getResources().getString(R.string.device_info_default);
+ Log.w(TAG, "Property " + PROPERTY_FRONT_CAMERA_SENSOR
+ + " has an unknown value of " + frontCameraSensor);
+ }
+
+ return info;
+ }
+
+ private String getCameraModuleInfo() {
+ final String mainCameraSensor = SystemProperties.get(PROPERTY_MAIN_CAMERA_SENSOR);
+ String info;
+
+ if (VALUE_MAIN_CAMERA_SENSOR_OV8865.equals(mainCameraSensor)) {
+ info = getResources().getString(R.string.camera_module_ov8865);
+ } else if (VALUE_MAIN_CAMERA_SENSOR_OV12870.equals(mainCameraSensor)) {
+ info = getResources().getString(R.string.camera_module_ov12870);
+ } else {
+ // Unexpected property value, or missing
+ info = getResources().getString(R.string.device_info_default);
+ Log.w(TAG, "Property " + PROPERTY_MAIN_CAMERA_SENSOR
+ + " has an unknown value of " + mainCameraSensor);
+ }
+
+ return info;
+ }
+
+ private String getBatteryModuleInfo() {
+ final BatteryModule module = BatteryModule.getModule(getContext());
+ String info;
+
+ if (module != null) {
+ info = getResources().getString(R.string.battery_module_summary,
+ module.getVersionId(), module.getDesignCapacity());
+ } else {
+ info = getResources().getString(R.string.device_info_default);
+
+ Log.w(TAG, "Unknown battery module, property " + KEY_BATTERY_MODULE_INFO
+ + " set to default value");
+ }
+
+ return info;
+ }
}
diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
index f9555e2..d745115 100644
--- a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
+++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
@@ -89,7 +89,8 @@
private void updateDialogForCdmaPhone() {
final Resources res = mDialog.getContext().getResources();
- mDialog.setText(ID_MEID_NUMBER_VALUE, getMeid());
+ mDialog.setText(ID_MEID_NUMBER_VALUE,
+ mSubscriptionInfo != null ? getMeid() : "");
mDialog.setText(ID_MIN_NUMBER_VALUE,
mSubscriptionInfo != null ? mTelephonyManager.getCdmaMin(
mSubscriptionInfo.getSubscriptionId()) : "");
@@ -114,9 +115,13 @@
}
private void updateDialogForGsmPhone() {
- mDialog.setText(ID_IMEI_VALUE, getTextAsDigits(mTelephonyManager.getImei(mSlotId)));
+ mDialog.setText(ID_IMEI_VALUE,
+ mSubscriptionInfo != null ?
+ getTextAsDigits(mTelephonyManager.getImei(mSlotId)) : "");
mDialog.setText(ID_IMEI_SV_VALUE,
- getTextAsDigits(mTelephonyManager.getDeviceSoftwareVersion(mSlotId)));
+ mSubscriptionInfo != null ?
+ getTextAsDigits(mTelephonyManager.
+ getDeviceSoftwareVersion(mSlotId)) : "");
// device is not CDMA, do not display CDMA features
mDialog.removeViewFromScreen(ID_CDMA_SETTINGS);
}
@@ -127,8 +132,12 @@
if (subscriptionInfoList == null) {
return null;
}
-
- return subscriptionInfoList.get(slotId);
+ for (SubscriptionInfo info : subscriptionInfoList) {
+ if (slotId == info.getSimSlotIndex()) {
+ return info;
+ }
+ }
+ return null;
}
@VisibleForTesting
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index 7cbf318..76daa62 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -409,11 +409,15 @@
private SubscriptionInfo getPhoneSubscriptionInfo(int slotId) {
final List<SubscriptionInfo> subscriptionInfoList = SubscriptionManager.from(
mContext).getActiveSubscriptionInfoList();
- if (subscriptionInfoList != null && subscriptionInfoList.size() > slotId) {
- return subscriptionInfoList.get(slotId);
- } else {
+ if (subscriptionInfoList == null) {
return null;
}
+ for (SubscriptionInfo info : subscriptionInfoList) {
+ if (slotId == info.getSimSlotIndex()) {
+ return info;
+ }
+ }
+ return null;
}
@VisibleForTesting
diff --git a/src/com/android/settings/security/CryptKeeperSettings.java b/src/com/android/settings/security/CryptKeeperSettings.java
index 64f5abb..f6b510a 100644
--- a/src/com/android/settings/security/CryptKeeperSettings.java
+++ b/src/com/android/settings/security/CryptKeeperSettings.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2020-2021 Fairphone B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,6 +59,7 @@
private Button mInitiateButton;
private View mPowerWarning;
private View mBatteryWarning;
+ private View mUnsupportedMesssage;
private IntentFilter mIntentFilter;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -76,9 +78,12 @@
invalidCharger == 0;
// Update UI elements based on power/battery status
- mInitiateButton.setEnabled(levelOk && pluggedOk);
- mPowerWarning.setVisibility(pluggedOk ? View.GONE : View.VISIBLE );
- mBatteryWarning.setVisibility(levelOk ? View.GONE : View.VISIBLE);
+ // mInitiateButton.setEnabled(levelOk && pluggedOk);
+ // mPowerWarning.setVisibility(pluggedOk ? View.GONE : View.VISIBLE );
+ // mBatteryWarning.setVisibility(levelOk ? View.GONE : View.VISIBLE);
+
+ // Encryption is disabled in the current version of Fairphone OS.
+ mInitiateButton.setEnabled(false);
}
}
};
@@ -116,6 +121,7 @@
mPowerWarning = mContentView.findViewById(R.id.warning_unplugged);
mBatteryWarning = mContentView.findViewById(R.id.warning_low_charge);
+ mUnsupportedMesssage = mContentView.findViewById(R.id.message_unsupported);
return mContentView;
}
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index 853f80d..4b68430 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -40,6 +40,8 @@
import android.widget.Toast;
import com.android.settings.R;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
import java.util.ArrayList;
import java.util.Iterator;
@@ -96,6 +98,7 @@
PhoneAccountHandle phoneAccountHandle =
subscriptionIdToPhoneAccountHandle(subId);
setDefaultDataSubId(context, subId);
+ setPreferredNetworkMode(context, subId);
setDefaultSmsSubId(context, subId);
setUserSelectedOutgoingPhoneAccount(phoneAccountHandle);
finish();
@@ -115,6 +118,41 @@
}
}
+ private void setPreferredNetworkMode(Context context,int subId) {
+ final Phone[] phones = (Phone[])PhoneFactory.getPhones();
+ final Phone mPhone1, mPhone2;
+
+ // As we have only 2 slot
+ mPhone1 = phones[0];
+ mPhone2 = phones[1];
+
+ if (mPhone1.getSubId() == subId ) {
+ android.provider.Settings.Global.putInt(
+ context.getContentResolver(),
+ android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mPhone2.getSubId(),
+ Phone.NT_MODE_GSM_ONLY);
+ mPhone2.setPreferredNetworkType(Phone.NT_MODE_GSM_ONLY, null);
+
+ android.provider.Settings.Global.putInt(
+ context.getContentResolver(),
+ android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mPhone1.getSubId(),
+ Phone.NT_MODE_LTE_GSM_WCDMA);
+ mPhone1.setPreferredNetworkType(Phone.NT_MODE_LTE_GSM_WCDMA, null);
+ } else {
+ android.provider.Settings.Global.putInt(
+ context.getContentResolver(),
+ android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mPhone1.getSubId(),
+ Phone.NT_MODE_GSM_ONLY);
+ mPhone1.setPreferredNetworkType(Phone.NT_MODE_GSM_ONLY, null);
+
+ android.provider.Settings.Global.putInt(
+ context.getContentResolver(),
+ android.provider.Settings.Global.PREFERRED_NETWORK_MODE + mPhone2.getSubId(),
+ Phone.NT_MODE_LTE_GSM_WCDMA);
+ mPhone2.setPreferredNetworkType(Phone.NT_MODE_LTE_GSM_WCDMA, null);
+ }
+ }
+
private static void setDefaultDataSubId(final Context context, final int subId) {
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
subscriptionManager.setDefaultDataSubId(subId);
@@ -166,6 +204,7 @@
case DATA_PICK:
sir = subInfoList.get(value);
setDefaultDataSubId(context, sir.getSubscriptionId());
+ setPreferredNetworkMode(context, sir.getSubscriptionId());
break;
case CALLS_PICK:
final TelecomManager telecomManager =