009: Closure wave 3 deblob, handoff, and optional wave4/malloc bacons.
Ship script gates wave 4 behind AXP_DEBLOB_WAVE4, documents secrets cert path, and adds deblob appliers plus tests; docs capture Swissquote fix and parity. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
deaaf42caa
commit
3f941e8451
64 files changed
+6270
-86
No files matched your search
Vendored
+153
@@ -0,0 +1,153 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: anupritaisno1 <www.anuprita804@gmail.com>
|
||||
Date: Mon, 18 Oct 2021 01:35:40 +0300
|
||||
Subject: [PATCH] automatically reboot device after timeout if set
|
||||
|
||||
Signed-off-by: anupritaisno1 <www.anuprita804@gmail.com>
|
||||
Change-Id: If891bfbcc144c9336ba013260bad2b7c7a59c054
|
||||
---
|
||||
core/java/android/provider/Settings.java | 7 ++++
|
||||
data/etc/com.android.systemui.xml | 1 +
|
||||
packages/SystemUI/AndroidManifest.xml | 3 ++
|
||||
.../keyguard/KeyguardViewMediator.java | 35 +++++++++++++++++++
|
||||
4 files changed, 46 insertions(+)
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 783483d8e491..48913891ac52 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19027,6 +19027,13 @@ public final class Settings {
|
||||
public static final String REVIEW_PERMISSIONS_NOTIFICATION_STATE =
|
||||
"review_permissions_notification_state";
|
||||
|
||||
+ /**
|
||||
+ * Whether to automatically reboot the device after a user defined timeout
|
||||
+ *
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String SETTINGS_REBOOT_AFTER_TIMEOUT = "settings_reboot_after_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
|
||||
index ce2543a47cf5..67108d16e099 100644
|
||||
--- a/data/etc/com.android.systemui.xml
|
||||
+++ b/data/etc/com.android.systemui.xml
|
||||
@@ -54,6 +54,7 @@
|
||||
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
|
||||
<permission name="android.permission.READ_WALLPAPER_INTERNAL"/>
|
||||
<permission name="android.permission.REAL_GET_TASKS"/>
|
||||
+ <permission name="android.permission.REBOOT"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
<permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
|
||||
<permission name="android.permission.SATELLITE_COMMUNICATION"/>
|
||||
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
|
||||
index 351cce0929b7..00604a316019 100644
|
||||
--- a/packages/SystemUI/AndroidManifest.xml
|
||||
+++ b/packages/SystemUI/AndroidManifest.xml
|
||||
@@ -356,6 +356,9 @@
|
||||
|
||||
<uses-permission android:name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
|
||||
|
||||
+ <!-- Permission to allow rebooting the device after a user configurable amount of time -->
|
||||
+ <uses-permission android:name="android.permission.REBOOT" />
|
||||
+
|
||||
<uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
|
||||
|
||||
<uses-permission android:name="android.permission.MONITOR_STICKY_MODIFIER_STATE" />
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
index 6034e92be873..67dd84e8ae8f 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
|
||||
@@ -240,6 +240,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
|
||||
private final static String TAG = "KeyguardViewMediator";
|
||||
|
||||
+ private static final String DELAYED_REBOOT_ACTION =
|
||||
+ "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_REBOOT";
|
||||
public static final String DELAYED_KEYGUARD_ACTION =
|
||||
"com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
|
||||
private static final String DELAYED_LOCK_PROFILE_ACTION =
|
||||
@@ -417,6 +419,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
*/
|
||||
private int mDelayedProfileShowingSequence;
|
||||
|
||||
+ /**
|
||||
+ * Same as {@link #mDelayedProfileShowingSequence}, but used for our reboot implementation
|
||||
+ */
|
||||
+ private int mDelayedRebootSequence;
|
||||
+
|
||||
private final DismissCallbackRegistry mDismissCallbackRegistry;
|
||||
|
||||
// the properties of the keyguard
|
||||
@@ -1503,6 +1510,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
final IntentFilter delayedActionFilter = new IntentFilter();
|
||||
delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
|
||||
delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
|
||||
+ delayedActionFilter.addAction(DELAYED_REBOOT_ACTION);
|
||||
delayedActionFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
|
||||
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
|
||||
SYSTEMUI_PERMISSION, null /* scheduler */,
|
||||
@@ -1866,6 +1874,18 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
}
|
||||
}
|
||||
|
||||
+ private void doRebootForOwnerAfterTimeoutIfEnabled(long rebootAfterTimeout) {
|
||||
+ long when = mSystemClock.elapsedRealtime() + rebootAfterTimeout;
|
||||
+ Intent rebootIntent = new Intent(DELAYED_REBOOT_ACTION);
|
||||
+ rebootIntent.putExtra("seq", mDelayedRebootSequence);
|
||||
+ rebootIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||
+ PendingIntent sender = PendingIntent.getBroadcast(mContext,
|
||||
+ 0, rebootIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
|
||||
+ if (DEBUG) Log.d(TAG, "setting alarm to reboot device, timeout = "
|
||||
+ + String.valueOf(rebootAfterTimeout));
|
||||
+ }
|
||||
+
|
||||
private void doKeyguardForChildProfilesLocked() {
|
||||
for (UserInfo profile : mUserTracker.getUserProfiles()) {
|
||||
if (!profile.isEnabled()) continue;
|
||||
@@ -1884,6 +1904,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
mDelayedProfileShowingSequence++;
|
||||
}
|
||||
|
||||
+ private void cancelDoRebootForOwnerAfterTimeoutIfEnabled() {
|
||||
+ mDelayedRebootSequence++;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* It will let us know when the device is waking up.
|
||||
*/
|
||||
@@ -2298,6 +2322,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
|
||||
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
|
||||
showKeyguard(options);
|
||||
+ final long rebootAfterTimeout = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, 0);
|
||||
+ if (rebootAfterTimeout >= 1) {
|
||||
+ doRebootForOwnerAfterTimeoutIfEnabled(rebootAfterTimeout);
|
||||
+ }
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@@ -2478,6 +2506,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } else if (DELAYED_REBOOT_ACTION.equals(intent.getAction())) {
|
||||
+ final int sequence = intent.getIntExtra("seq", 0);
|
||||
+ if (sequence == mDelayedRebootSequence) {
|
||||
+ PowerManager pm = mContext.getSystemService(PowerManager.class);
|
||||
+ pm.reboot(null);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -3200,6 +3234,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
|
||||
mHideAnimationRun = false;
|
||||
adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
+ cancelDoRebootForOwnerAfterTimeoutIfEnabled();
|
||||
}
|
||||
|
||||
private Configuration.Builder createInteractionJankMonitorConf(int cuj) {
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Tue, 6 Sep 2022 16:48:26 +0300
|
||||
Subject: [PATCH] bugfix: Bluetooth auto turn off ignored connected BLE devices
|
||||
|
||||
Previous attempt at fixing this didn't work properly, because getConnectionStateLeAware() didn't
|
||||
actually report BLE state.
|
||||
---
|
||||
.../android/server/ext/BluetoothAutoOff.java | 20 ++++++++++++++-----
|
||||
1 file changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/services/core/java/com/android/server/ext/BluetoothAutoOff.java b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
index 4e7dbc042f37..a091b006214f 100644
|
||||
--- a/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
+++ b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
@@ -3,6 +3,7 @@ package com.android.server.ext;
|
||||
import android.annotation.Nullable;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
+import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -12,12 +13,14 @@ import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
|
||||
class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
+ private final BluetoothManager manager;
|
||||
@Nullable
|
||||
private final BluetoothAdapter adapter;
|
||||
|
||||
BluetoothAutoOff(SystemServerExt sse) {
|
||||
super(sse, sse.bgHandler);
|
||||
- adapter = sse.context.getSystemService(BluetoothManager.class).getAdapter();
|
||||
+ manager = sse.context.getSystemService(BluetoothManager.class);
|
||||
+ adapter = manager.getAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,11 +54,18 @@ class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
|
||||
private boolean isAdapterOnAndDisconnected() {
|
||||
if (adapter != null) {
|
||||
- int state = adapter.getLeStateSysApi(); // getState() converts BLE states into STATE_OFF
|
||||
+ if (adapter.isLeEnabled()) {
|
||||
+ if (adapter.getConnectionState() == BluetoothAdapter.STATE_DISCONNECTED) {
|
||||
+ // Bluetooth GATT Profile (Bluetooth LE) connection state is ignored
|
||||
+ // by getConnectionState()
|
||||
+ return manager.getConnectedDevices(BluetoothProfile.GATT).size() == 0;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
- // getConnectionState() converts BLE states into STATE_DISCONNECTED
|
||||
- return adapter.getConnectionStateLeAware() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
+ // isLeEnabled() currently implies isEnabled(), but check again anyway in case
|
||||
+ // this changes in the future
|
||||
+ if (adapter.isEnabled()) {
|
||||
+ return adapter.getConnectionState() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Sun, 31 Jul 2022 11:19:33 +0300
|
||||
Subject: [PATCH] Bluetooth auto turn off
|
||||
|
||||
Co-authored-by: Pratyush <codelab@pratyush.dev>
|
||||
---
|
||||
core/java/android/provider/Settings.java | 6 ++
|
||||
.../android/server/ext/BluetoothAutoOff.java | 69 +++++++++++++++++++
|
||||
.../android/server/ext/SystemServerExt.java | 4 ++
|
||||
3 files changed, 79 insertions(+)
|
||||
create mode 100644 services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 49f59950b9e0..58f1077af988 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19549,6 +19549,12 @@ public final class Settings {
|
||||
*/
|
||||
public static final String WIFI_OFF_TIMEOUT = "wifi_off_timeout";
|
||||
|
||||
+ /**
|
||||
+ * The amount of time in milliseconds before a disconnected Bluetooth adapter is turned off
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String BLUETOOTH_OFF_TIMEOUT = "bluetooth_off_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/services/core/java/com/android/server/ext/BluetoothAutoOff.java b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
new file mode 100644
|
||||
index 000000000000..4e7dbc042f37
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/BluetoothAutoOff.java
|
||||
@@ -0,0 +1,69 @@
|
||||
+package com.android.server.ext;
|
||||
+
|
||||
+import android.annotation.Nullable;
|
||||
+import android.bluetooth.BluetoothAdapter;
|
||||
+import android.bluetooth.BluetoothManager;
|
||||
+import android.content.BroadcastReceiver;
|
||||
+import android.content.Context;
|
||||
+import android.content.Intent;
|
||||
+import android.content.IntentFilter;
|
||||
+import android.os.Build;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Slog;
|
||||
+
|
||||
+class BluetoothAutoOff extends DelayedConditionalAction {
|
||||
+ @Nullable
|
||||
+ private final BluetoothAdapter adapter;
|
||||
+
|
||||
+ BluetoothAutoOff(SystemServerExt sse) {
|
||||
+ super(sse, sse.bgHandler);
|
||||
+ adapter = sse.context.getSystemService(BluetoothManager.class).getAdapter();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean shouldScheduleAlarm() {
|
||||
+ return isAdapterOnAndDisconnected();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void alarmTriggered() {
|
||||
+ if (isAdapterOnAndDisconnected()) {
|
||||
+ adapter.disable();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void registerStateListener() {
|
||||
+ IntentFilter f = new IntentFilter();
|
||||
+ f.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
+ f.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
|
||||
+
|
||||
+ sse.registerReceiver(new BroadcastReceiver() {
|
||||
+ @Override
|
||||
+ public void onReceive(Context broadcastContext, Intent intent) {
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ Slog.d("BtAutoOff", "" + intent + ", extras " + intent.getExtras().deepCopy());
|
||||
+ }
|
||||
+ update();
|
||||
+ }
|
||||
+ }, f, handler);
|
||||
+ }
|
||||
+
|
||||
+ private boolean isAdapterOnAndDisconnected() {
|
||||
+ if (adapter != null) {
|
||||
+ int state = adapter.getLeStateSysApi(); // getState() converts BLE states into STATE_OFF
|
||||
+
|
||||
+ if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
+ // getConnectionState() converts BLE states into STATE_DISCONNECTED
|
||||
+ return adapter.getConnectionStateLeAware() == BluetoothAdapter.STATE_DISCONNECTED;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String getDelayGlobalSettingsKey() {
|
||||
+ return Settings.Global.BLUETOOTH_OFF_TIMEOUT;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
index 66350e2b7f74..3c341ed25f4e 100644
|
||||
--- a/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
@@ -53,6 +53,10 @@ public final class SystemServerExt {
|
||||
if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI, 0)) {
|
||||
new WifiAutoOff(this);
|
||||
}
|
||||
+
|
||||
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH, 0)) {
|
||||
+ new BluetoothAutoOff(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Sun, 31 Jul 2022 10:06:14 +0300
|
||||
Subject: [PATCH] infrastructure for system_server extensions
|
||||
|
||||
---
|
||||
.../server/ext/DelayedConditionalAction.java | 135 ++++++++++++++++++
|
||||
.../android/server/ext/SystemServerExt.java | 58 ++++++++
|
||||
.../java/com/android/server/SystemServer.java | 2 +
|
||||
3 files changed, 195 insertions(+)
|
||||
create mode 100644 services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
||||
create mode 100644 services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
|
||||
diff --git a/services/core/java/com/android/server/ext/DelayedConditionalAction.java b/services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
||||
new file mode 100644
|
||||
index 000000000000..d72f302e9d42
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/DelayedConditionalAction.java
|
||||
@@ -0,0 +1,135 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2022 GrapheneOS
|
||||
+ *
|
||||
+ * 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.server.ext;
|
||||
+
|
||||
+import android.app.AlarmManager;
|
||||
+import android.content.ContentResolver;
|
||||
+import android.content.Context;
|
||||
+import android.database.ContentObserver;
|
||||
+import android.net.Uri;
|
||||
+import android.os.Build;
|
||||
+import android.os.Handler;
|
||||
+import android.os.Looper;
|
||||
+import android.os.SystemClock;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Slog;
|
||||
+
|
||||
+/**
|
||||
+ * Infrastructure for actions that:
|
||||
+ * - happen after a user-configurable device-wide (Settings.Global) delay
|
||||
+ * - need to be taken even when the device is in deep sleep
|
||||
+ * - need to be rescheduled based on some listenable event
|
||||
+ */
|
||||
+public abstract class DelayedConditionalAction {
|
||||
+ private static final String TAG = "DelayedConditionalAction";
|
||||
+
|
||||
+ protected final SystemServerExt sse;
|
||||
+ protected final Thread thread;
|
||||
+ protected final Handler handler;
|
||||
+
|
||||
+ protected final ContentResolver contentResolver;
|
||||
+ protected final AlarmManager alarmManager;
|
||||
+ private final AlarmManager.OnAlarmListener alarmListener;
|
||||
+
|
||||
+ protected DelayedConditionalAction(SystemServerExt sse, Handler handler) {
|
||||
+ this.sse = sse;
|
||||
+
|
||||
+ Looper looper = handler.getLooper();
|
||||
+ thread = looper.getThread();
|
||||
+ this.handler = handler;
|
||||
+
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ if (thread != Thread.currentThread()) {
|
||||
+ throw new IllegalStateException("all calls should happen on the same thread");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ Context ctx = sse.context;
|
||||
+ contentResolver = ctx.getContentResolver();
|
||||
+ alarmManager = ctx.getSystemService(AlarmManager.class);
|
||||
+
|
||||
+ alarmListener = () -> {
|
||||
+ if (delayDurationMillis() == 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ alarmTriggered();
|
||||
+ };
|
||||
+
|
||||
+ registerStateListener();
|
||||
+
|
||||
+ Uri delaySettingUri = Settings.Global.getUriFor(getDelayGlobalSettingsKey());
|
||||
+
|
||||
+ ContentObserver delayChangeListener = new ContentObserver(handler) {
|
||||
+ @Override
|
||||
+ public void onChange(boolean selfChange) {
|
||||
+ update();
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ contentResolver.registerContentObserver(delaySettingUri, false, delayChangeListener);
|
||||
+ }
|
||||
+
|
||||
+ private boolean alarmScheduled;
|
||||
+
|
||||
+ protected final void update() {
|
||||
+ final Thread curThread = Thread.currentThread();
|
||||
+ if (curThread != thread) {
|
||||
+ String msg = "update() called on an unknown thread " + curThread;
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ throw new IllegalStateException(msg);
|
||||
+ } else {
|
||||
+ Slog.e(TAG, msg, new Throwable());
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (alarmScheduled) {
|
||||
+ alarmManager.cancel(alarmListener);
|
||||
+ alarmScheduled = false;
|
||||
+ }
|
||||
+
|
||||
+ if (!shouldScheduleAlarm()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ long delayMillis = delayDurationMillis();
|
||||
+
|
||||
+ if (delayMillis == 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ final long triggerAt = SystemClock.elapsedRealtime() + delayMillis;
|
||||
+ alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAt,
|
||||
+ getClass().getName(), alarmListener, handler);
|
||||
+ alarmScheduled = true;
|
||||
+ }
|
||||
+
|
||||
+ private long delayDurationMillis() {
|
||||
+ return Settings.Global.getLong(contentResolver, getDelayGlobalSettingsKey(), 0);
|
||||
+ }
|
||||
+
|
||||
+ // Make sure to use the same Handler that is used for all other callbacks;
|
||||
+ // call update() to reschedule / cancel the alarm
|
||||
+ protected abstract void registerStateListener();
|
||||
+
|
||||
+ protected abstract boolean shouldScheduleAlarm();
|
||||
+ protected abstract void alarmTriggered();
|
||||
+
|
||||
+ // android.provider.Settings.Global key
|
||||
+ protected abstract String getDelayGlobalSettingsKey();
|
||||
+}
|
||||
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
new file mode 100644
|
||||
index 000000000000..83d895650473
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
@@ -0,0 +1,58 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2022 GrapheneOS
|
||||
+ *
|
||||
+ * 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.server.ext;
|
||||
+
|
||||
+import android.content.BroadcastReceiver;
|
||||
+import android.content.Context;
|
||||
+import android.content.IntentFilter;
|
||||
+import android.os.Handler;
|
||||
+
|
||||
+import com.android.internal.os.BackgroundThread;
|
||||
+import com.android.server.pm.PackageManagerService;
|
||||
+
|
||||
+public final class SystemServerExt {
|
||||
+
|
||||
+ public final Context context;
|
||||
+ public final Handler bgHandler;
|
||||
+ public final PackageManagerService packageManager;
|
||||
+
|
||||
+ private SystemServerExt(Context systemContext, PackageManagerService pm) {
|
||||
+ context = systemContext;
|
||||
+ bgHandler = BackgroundThread.getHandler();
|
||||
+ packageManager = pm;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ Called after system server has completed its initialization,
|
||||
+ but before any of the apps are started.
|
||||
+
|
||||
+ Call from com.android.server.SystemServer#startOtherServices(), at the end of lambda
|
||||
+ that is passed into mActivityManagerService.systemReady()
|
||||
+ */
|
||||
+ public static void init(Context systemContext, PackageManagerService pm) {
|
||||
+ SystemServerExt sse = new SystemServerExt(systemContext, pm);
|
||||
+ sse.bgHandler.post(sse::initBgThread);
|
||||
+ }
|
||||
+
|
||||
+ void initBgThread() {
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
||||
+ context.registerReceiver(receiver, filter, null, handler);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
|
||||
index e92ba3ed7dc3..df60c628ccdb 100644
|
||||
--- a/services/java/com/android/server/SystemServer.java
|
||||
+++ b/services/java/com/android/server/SystemServer.java
|
||||
@@ -3454,6 +3454,8 @@ public final class SystemServer implements Dumpable {
|
||||
reportWtf("Triggering OdsignStatsLogger", e);
|
||||
}
|
||||
t.traceEnd();
|
||||
+
|
||||
+ com.android.server.ext.SystemServerExt.init(mSystemContext, mPackageManagerService);
|
||||
}, t);
|
||||
|
||||
t.traceBegin("LockSettingsThirdPartyAppsStarted");
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Sun, 31 Jul 2022 10:06:14 +0300
|
||||
Subject: [PATCH] Wi-Fi auto turn off
|
||||
|
||||
Co-authored-by: Pratyush <codelab@pratyush.dev>
|
||||
---
|
||||
core/java/android/provider/Settings.java | 6 ++
|
||||
.../android/server/ext/SystemServerExt.java | 5 +-
|
||||
.../com/android/server/ext/WifiAutoOff.java | 69 +++++++++++++++++++
|
||||
3 files changed, 79 insertions(+), 1 deletion(-)
|
||||
create mode 100644 services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
|
||||
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
|
||||
index 10efaa78e435..49f59950b9e0 100644
|
||||
--- a/core/java/android/provider/Settings.java
|
||||
+++ b/core/java/android/provider/Settings.java
|
||||
@@ -19543,6 +19543,12 @@ public final class Settings {
|
||||
*/
|
||||
public static final String SETTINGS_REBOOT_AFTER_TIMEOUT = "settings_reboot_after_timeout";
|
||||
|
||||
+ /**
|
||||
+ * The amount of time in milliseconds before a disconnected Wi-Fi adapter is turned off
|
||||
+ * @hide
|
||||
+ */
|
||||
+ public static final String WIFI_OFF_TIMEOUT = "wifi_off_timeout";
|
||||
+
|
||||
/**
|
||||
* Whether repair mode is active on the device.
|
||||
* <p>
|
||||
diff --git a/services/core/java/com/android/server/ext/SystemServerExt.java b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
index 83d895650473..66350e2b7f74 100644
|
||||
--- a/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
+++ b/services/core/java/com/android/server/ext/SystemServerExt.java
|
||||
@@ -19,6 +19,7 @@ package com.android.server.ext;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
+import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
@@ -49,7 +50,9 @@ public final class SystemServerExt {
|
||||
}
|
||||
|
||||
void initBgThread() {
|
||||
-
|
||||
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI, 0)) {
|
||||
+ new WifiAutoOff(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, Handler handler) {
|
||||
diff --git a/services/core/java/com/android/server/ext/WifiAutoOff.java b/services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
new file mode 100644
|
||||
index 000000000000..c7a3c05fe766
|
||||
--- /dev/null
|
||||
+++ b/services/core/java/com/android/server/ext/WifiAutoOff.java
|
||||
@@ -0,0 +1,69 @@
|
||||
+package com.android.server.ext;
|
||||
+
|
||||
+import android.content.BroadcastReceiver;
|
||||
+import android.content.Context;
|
||||
+import android.content.Intent;
|
||||
+import android.content.IntentFilter;
|
||||
+import android.net.wifi.WifiInfo;
|
||||
+import android.net.wifi.WifiManager;
|
||||
+import android.os.Build;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Slog;
|
||||
+
|
||||
+class WifiAutoOff extends DelayedConditionalAction {
|
||||
+ private final WifiManager wifiManager;
|
||||
+
|
||||
+ WifiAutoOff(SystemServerExt sse) {
|
||||
+ super(sse, sse.bgHandler);
|
||||
+ wifiManager = sse.context.getSystemService(WifiManager.class);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected boolean shouldScheduleAlarm() {
|
||||
+ return isWifiEnabledAndNotConnected();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void alarmTriggered() {
|
||||
+ if (isWifiEnabledAndNotConnected()) {
|
||||
+ wifiManager.setWifiEnabled(false);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private boolean isWifiEnabledAndNotConnected() {
|
||||
+ if (wifiManager.isWifiEnabled()) {
|
||||
+ WifiInfo i = wifiManager.getConnectionInfo();
|
||||
+ if (i == null) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ return i.getBSSID() == null;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void registerStateListener() {
|
||||
+ IntentFilter f = new IntentFilter();
|
||||
+ f.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||
+ f.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
+ // ConnectivityManager APIs seem unfit for listening to Wi-Fi state specifically, they look
|
||||
+ // to be higher level than that, eg VPN over Wi-Fi isn't considered to be a Wi-Fi connection
|
||||
+ // by ConnectivityManager
|
||||
+
|
||||
+ sse.registerReceiver(new BroadcastReceiver() {
|
||||
+ @Override
|
||||
+ public void onReceive(Context context, Intent intent) {
|
||||
+ if (Build.isDebuggable()) {
|
||||
+ Slog.d("WifiAutoOff", "" + intent + ", extras " + intent.getExtras().deepCopy());
|
||||
+ }
|
||||
+ update();
|
||||
+ }
|
||||
+ }, f, handler);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected String getDelayGlobalSettingsKey() {
|
||||
+ return Settings.Global.WIFI_OFF_TIMEOUT;
|
||||
+ }
|
||||
+}
|
||||
Vendored
+141
@@ -0,0 +1,141 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Muhomor <muhomor.dmitry@gmail.com>
|
||||
Date: Mon, 11 Mar 2024 19:40:18 +0200
|
||||
Subject: [PATCH] SystemUI: require unlocking to use QS tiles by default
|
||||
|
||||
---
|
||||
.../src/com/android/systemui/qs/QSHost.java | 1 +
|
||||
.../com/android/systemui/qs/QSHostAdapter.kt | 4 +++
|
||||
.../systemui/qs/tileimpl/QSTileImpl.java | 36 +++++++++++++++++--
|
||||
.../systemui/qs/QSHostAdapterKosmos.kt | 2 ++
|
||||
4 files changed, 40 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
index 7c7f48e0d37b..87e87348d0f2 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
|
||||
@@ -51,6 +51,7 @@ public interface QSHost {
|
||||
Context getUserContext();
|
||||
int getUserId();
|
||||
Collection<QSTile> getTiles();
|
||||
+ com.android.systemui.statusbar.policy.KeyguardStateController getKeyguardStateController();
|
||||
void addCallback(Callback callback);
|
||||
void removeCallback(Callback callback);
|
||||
void removeTile(String tileSpec);
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
index dc3b58247152..08f3fc9d7bdb 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt
|
||||
@@ -31,6 +31,7 @@ import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
|
||||
import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
|
||||
import com.android.systemui.qs.pipeline.shared.TileSpec
|
||||
import com.android.systemui.shade.ShadeDisplayAware
|
||||
+import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -53,6 +54,7 @@ constructor(
|
||||
@ShadeDisplayAware private val context: Context,
|
||||
private val tileServiceRequestControllerBuilder: TileServiceRequestController.Builder,
|
||||
@Application private val scope: CoroutineScope,
|
||||
+ private val keyguardStateController_: KeyguardStateController,
|
||||
dumpManager: DumpManager,
|
||||
) : QSHost {
|
||||
|
||||
@@ -72,6 +74,8 @@ constructor(
|
||||
return interactor.currentQSTiles
|
||||
}
|
||||
|
||||
+ override fun getKeyguardStateController() = keyguardStateController_
|
||||
+
|
||||
override fun getSpecs(): List<String> {
|
||||
return interactor.currentTilesSpecs.map { it.spec }
|
||||
}
|
||||
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
index 1d1e9911884c..e9dc57e4c47d 100644
|
||||
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
|
||||
@@ -71,6 +71,7 @@ import com.android.systemui.qs.QsEventLogger;
|
||||
import com.android.systemui.qs.SideLabelTileLayout;
|
||||
import com.android.systemui.qs.flags.QsInCompose;
|
||||
import com.android.systemui.qs.logging.QSLogger;
|
||||
+import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Objects;
|
||||
@@ -272,6 +273,32 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
return true;
|
||||
}
|
||||
|
||||
+ public enum Action {
|
||||
+ CLICK,
|
||||
+ SECONDARY_CLICK,
|
||||
+ LONG_CLICK,
|
||||
+ }
|
||||
+
|
||||
+ public boolean isAllowedWhenLocked(Action action) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ void handleAction(Action action, Runnable handler) {
|
||||
+ if (isAllowedWhenLocked(action)) {
|
||||
+ handler.run();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ KeyguardStateController ksc = mHost.getKeyguardStateController();
|
||||
+ boolean hasSecureKeyguard = ksc.isMethodSecure() && ksc.isShowing();
|
||||
+
|
||||
+ if (hasSecureKeyguard) {
|
||||
+ mActivityStarter.postQSRunnableDismissingKeyguard(handler);
|
||||
+ } else {
|
||||
+ handler.run();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// safe to call from any thread
|
||||
|
||||
public void addCallback(Callback callback) {
|
||||
@@ -616,16 +643,19 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
|
||||
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
|
||||
} else {
|
||||
mQSLogger.logHandleClick(mTileSpec, msg.arg1);
|
||||
- handleClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.CLICK, () -> handleClick(view));
|
||||
}
|
||||
} else if (msg.what == SECONDARY_CLICK) {
|
||||
name = "handleSecondaryClick";
|
||||
mQSLogger.logHandleSecondaryClick(mTileSpec, msg.arg1);
|
||||
- handleSecondaryClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.SECONDARY_CLICK, () -> handleSecondaryClick(view));
|
||||
} else if (msg.what == LONG_CLICK) {
|
||||
name = "handleLongClick";
|
||||
mQSLogger.logHandleLongClick(mTileSpec, msg.arg1);
|
||||
- handleLongClick((Expandable) msg.obj);
|
||||
+ Expandable view = (Expandable) msg.obj;
|
||||
+ handleAction(Action.LONG_CLICK, () -> handleLongClick(view));
|
||||
} else if (msg.what == REFRESH_STATE) {
|
||||
name = "handleRefreshState";
|
||||
handleRefreshState(msg.obj);
|
||||
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
index 0bf801b35ad1..7cb93459077c 100644
|
||||
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QSHostAdapterKosmos.kt
|
||||
@@ -22,6 +22,7 @@ import com.android.systemui.kosmos.Kosmos
|
||||
import com.android.systemui.kosmos.applicationCoroutineScope
|
||||
import com.android.systemui.qs.external.tileServiceRequestControllerBuilder
|
||||
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
|
||||
+import com.android.systemui.statusbar.policy.keyguardStateController
|
||||
|
||||
val Kosmos.qsHostAdapter by
|
||||
Kosmos.Fixture {
|
||||
@@ -30,6 +31,7 @@ val Kosmos.qsHostAdapter by
|
||||
applicationContext,
|
||||
tileServiceRequestControllerBuilder,
|
||||
applicationCoroutineScope,
|
||||
+ keyguardStateController,
|
||||
dumpManager,
|
||||
)
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: pratyush <codelab@pratyush.dev>
|
||||
Date: Mon, 7 Jun 2021 22:15:59 +0100
|
||||
Subject: [PATCH] add auto-reboot setting
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 31 +++++++
|
||||
res/values/strings.xml | 3 +
|
||||
res/xml/security_dashboard_settings.xml | 10 ++-
|
||||
.../AutoRebootPreferenceController.java | 82 +++++++++++++++++++
|
||||
.../settings/security/SecuritySettings.java | 1 +
|
||||
5 files changed, 126 insertions(+), 1 deletion(-)
|
||||
create mode 100644 src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index febdb0412a4..c5df677975d 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -105,6 +105,37 @@
|
||||
<item>1800000</item>
|
||||
</string-array>
|
||||
|
||||
+ <!-- Auto reboot settings -->
|
||||
+ <string-array name="auto_reboot_entries">
|
||||
+ <item>Off</item>
|
||||
+ <item>10 minutes</item>
|
||||
+ <item>30 minutes</item>
|
||||
+ <item>1 hour</item>
|
||||
+ <item>2 hours</item>
|
||||
+ <item>4 hours</item>
|
||||
+ <item>8 hours</item>
|
||||
+ <item>12 hours</item>
|
||||
+ <item>24 hours</item>
|
||||
+ <item>36 hours</item>
|
||||
+ <item>48 hours</item>
|
||||
+ <item>72 hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <string-array name="auto_reboot_values" translatable="false">
|
||||
+ <item>0</item> <!-- Disabled -->
|
||||
+ <item>600000</item>
|
||||
+ <item>1800000</item>
|
||||
+ <item>3600000</item>
|
||||
+ <item>7200000</item>
|
||||
+ <item>14400000</item>
|
||||
+ <item>28800000</item>
|
||||
+ <item>43200000</item>
|
||||
+ <item>86400000</item>
|
||||
+ <item>129600000</item>
|
||||
+ <item>172800000</item>
|
||||
+ <item>259200000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Wi-Fi settings -->
|
||||
|
||||
<!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index 2e44c013a96..b7105938345 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -675,6 +675,9 @@
|
||||
<!-- Text shown for title of owner info setting [CHAR LIMIT=30]-->
|
||||
<string name="owner_info_settings_title">Add text on lock screen</string>
|
||||
|
||||
+ <string name="auto_reboot_title">Auto reboot</string>
|
||||
+ <string name="auto_reboot_summary">Automatically reboot the device, if the phone hasn\'t been unlocked within the selected number of hours.</string>
|
||||
+
|
||||
<!-- Text shown for summary of owner info setting (if none set) [CHAR LIMIT=40]-->
|
||||
<string name="owner_info_settings_summary">None</string>
|
||||
<!-- Hint text shown in owner info edit text [CHAR LIMIT=50] -->
|
||||
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
|
||||
index 0550441d3f2..d0aeb27fe53 100644
|
||||
--- a/res/xml/security_dashboard_settings.xml
|
||||
+++ b/res/xml/security_dashboard_settings.xml
|
||||
@@ -60,6 +60,14 @@
|
||||
android:title="@string/security_settings_biometric_preference_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:keywords="@string/keywords_biometric_settings" />
|
||||
+
|
||||
+ <ListPreference
|
||||
+ android:key="auto_reboot"
|
||||
+ android:title="@string/auto_reboot_title"
|
||||
+ android:summary="@string/auto_reboot_summary"
|
||||
+ android:persistent="false"
|
||||
+ android:entries="@array/auto_reboot_entries"
|
||||
+ android:entryValues="@array/auto_reboot_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<Preference
|
||||
@@ -71,4 +79,4 @@
|
||||
settings:controller="com.android.settings.security.SecurityAdvancedSettingsController"
|
||||
settings:keywords="@string/security_advanced_settings_keywords" />
|
||||
|
||||
-</PreferenceScreen>
|
||||
\ No newline at end of file
|
||||
+</PreferenceScreen>
|
||||
diff --git a/src/com/android/settings/security/AutoRebootPreferenceController.java b/src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..c7a75219a5e
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/security/AutoRebootPreferenceController.java
|
||||
@@ -0,0 +1,82 @@
|
||||
+package com.android.settings.security;
|
||||
+
|
||||
+import android.content.Context;
|
||||
+import android.os.UserManager;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+import androidx.preference.PreferenceCategory;
|
||||
+import androidx.preference.PreferenceScreen;
|
||||
+
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+import com.android.settingslib.core.AbstractPreferenceController;
|
||||
+import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
+
|
||||
+public class AutoRebootPreferenceController extends AbstractPreferenceController
|
||||
+ implements PreferenceControllerMixin, OnResume,
|
||||
+ Preference.OnPreferenceChangeListener {
|
||||
+
|
||||
+ private static final String KEY_AUTO_REBOOT = "auto_reboot";
|
||||
+ private static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
|
||||
+
|
||||
+ private PreferenceCategory mSecurityCategory;
|
||||
+ private boolean mIsAdmin;
|
||||
+ private final UserManager mUm;
|
||||
+
|
||||
+ public AutoRebootPreferenceController(Context context) {
|
||||
+ super(context);
|
||||
+ mUm = UserManager.get(context);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void displayPreference(PreferenceScreen screen) {
|
||||
+ super.displayPreference(screen);
|
||||
+ mSecurityCategory = screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
|
||||
+ updatePreferenceState();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isAvailable() {
|
||||
+ mIsAdmin = mUm.isAdminUser();
|
||||
+ return mIsAdmin;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return KEY_AUTO_REBOOT;
|
||||
+ }
|
||||
+
|
||||
+ // TODO: should we use onCreatePreferences() instead?
|
||||
+ private void updatePreferenceState() {
|
||||
+ if (mSecurityCategory == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (mIsAdmin) {
|
||||
+ ListPreference autoReboot =
|
||||
+ (ListPreference) mSecurityCategory.findPreference(KEY_AUTO_REBOOT);
|
||||
+ autoReboot.setValue(Long.toString(Settings.Global.getLong(
|
||||
+ mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, 0)));
|
||||
+ } else {
|
||||
+ mSecurityCategory.removePreference(
|
||||
+ mSecurityCategory.findPreference(KEY_AUTO_REBOOT));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onResume() {
|
||||
+ updatePreferenceState();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object value) {
|
||||
+ final String key = preference.getKey();
|
||||
+ if (KEY_AUTO_REBOOT.equals(key) && mIsAdmin) {
|
||||
+ long timeout = Long.parseLong((String) value);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.SETTINGS_REBOOT_AFTER_TIMEOUT, timeout);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java
|
||||
index 797d3ec621e..3f0645f7dd8 100644
|
||||
--- a/src/com/android/settings/security/SecuritySettings.java
|
||||
+++ b/src/com/android/settings/security/SecuritySettings.java
|
||||
@@ -114,6 +114,7 @@ public class SecuritySettings extends DashboardFragment {
|
||||
securityPreferenceControllers.add(new CombinedBiometricStatusPreferenceController(
|
||||
context, lifecycle));
|
||||
securityPreferenceControllers.add(new ChangeScreenLockPreferenceController(context, host));
|
||||
+ securityPreferenceControllers.add(new AutoRebootPreferenceController(context));
|
||||
controllers.add(new PreferenceCategoryController(context, SECURITY_CATEGORY)
|
||||
.setChildren(securityPreferenceControllers));
|
||||
controllers.addAll(securityPreferenceControllers);
|
||||
Vendored
+238
@@ -0,0 +1,238 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Oliver Scott <olivercscott@gmail.com>
|
||||
Date: Fri, 2 Oct 2020 12:37:30 -0400
|
||||
Subject: [PATCH] add bluetooth auto-turn-off setting
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 44 +++++++
|
||||
res/values/strings.xml | 19 +++
|
||||
res/xml/connected_devices.xml | 8 ++
|
||||
.../BluetoothTimeoutPreferenceController.java | 115 ++++++++++++++++++
|
||||
4 files changed, 186 insertions(+)
|
||||
create mode 100644 src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index c5df677975d..1a2796ad276 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -18,6 +18,50 @@
|
||||
*/
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
+ <!-- Bluetooth settings. The delay in inactivity before bluetooth is turned off. These are shown in a list dialog. -->
|
||||
+ <string-array name="bluetooth_timeout_entries">
|
||||
+ <item>@string/bluetooth_timeout_summary_never</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_15secs</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_30secs</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_1min</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_2mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_5mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_10mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_30mins</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_1hour</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_2hours</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_4hours</item>
|
||||
+ <item>@string/bluetooth_timeout_summary_8hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <!-- Do not translate. -->
|
||||
+ <string-array name="bluetooth_timeout_values" translatable="false">
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>0</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>15000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>30000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>60000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>120000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>300000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>1800000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>3600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>7200000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>14400000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>28800000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Display settings. The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
|
||||
<string-array name="screen_timeout_entries">
|
||||
<item>15 seconds</item>
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index b7105938345..cf41793fd42 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -27,6 +27,25 @@
|
||||
<!-- Used in confirmation dialogs as the action that the user will tap to turn on the feature. [CHAR LIMIT=40]-->
|
||||
<string name="confirmation_turn_on">Turn on</string>
|
||||
|
||||
+ <!-- Connected devices screen, setting option name to change bluetooth timeout -->
|
||||
+ <string name="bluetooth_timeout">Bluetooth timeout</string>
|
||||
+
|
||||
+ <!-- Connected devices screen, setting option summary to change bluetooth timeout -->
|
||||
+ <string name="bluetooth_timeout_summary">Bluetooth will turn off after <xliff:g id="timeout_description">%1$s</xliff:g> if no devices connected</string>
|
||||
+ <string name="bluetooth_timeout_summary2">Do not automatically turn off Bluetooth</string>
|
||||
+ <string name="bluetooth_timeout_summary_never">Never</string>
|
||||
+ <string name="bluetooth_timeout_summary_15secs">15 seconds</string>
|
||||
+ <string name="bluetooth_timeout_summary_30secs">30 seconds</string>
|
||||
+ <string name="bluetooth_timeout_summary_1min">1 minute</string>
|
||||
+ <string name="bluetooth_timeout_summary_2mins">2 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_5mins">5 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_10mins">10 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_30mins">30 minutes</string>
|
||||
+ <string name="bluetooth_timeout_summary_1hour">1 hour</string>
|
||||
+ <string name="bluetooth_timeout_summary_2hours">2 hours</string>
|
||||
+ <string name="bluetooth_timeout_summary_4hours">4 hours</string>
|
||||
+ <string name="bluetooth_timeout_summary_8hours">8 hours</string>
|
||||
+
|
||||
<!-- Device Info screen. Used for a status item's value when the proper value is not known -->
|
||||
<string name="device_info_default">Unknown</string>
|
||||
<!-- String for removal of sensitive info on about, depending on tap -->
|
||||
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
|
||||
index 95aa8773c68..d66915369e4 100644
|
||||
--- a/res/xml/connected_devices.xml
|
||||
+++ b/res/xml/connected_devices.xml
|
||||
@@ -60,6 +60,14 @@
|
||||
settings:useAdminDisabledSummary="true"
|
||||
settings:userRestriction="no_config_bluetooth" />
|
||||
|
||||
+ <androidx.preference.ListPreference
|
||||
+ android:key="bluetooth_timeout"
|
||||
+ android:title="@string/bluetooth_timeout"
|
||||
+ android:summary="@string/summary_placeholder"
|
||||
+ android:entries="@array/bluetooth_timeout_entries"
|
||||
+ android:entryValues="@array/bluetooth_timeout_values"
|
||||
+ settings:controller="com.android.settings.bluetooth.BluetoothTimeoutPreferenceController"/>
|
||||
+
|
||||
<PreferenceCategory
|
||||
android:key="previously_connected_devices"
|
||||
android:title="@string/connected_device_saved_title"
|
||||
diff --git a/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..244147948aa
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/bluetooth/BluetoothTimeoutPreferenceController.java
|
||||
@@ -0,0 +1,115 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2020 The Calyx Institute
|
||||
+ *
|
||||
+ * 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.bluetooth;
|
||||
+
|
||||
+import android.bluetooth.BluetoothAdapter;
|
||||
+import android.content.Context;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+
|
||||
+import com.android.settings.R;
|
||||
+import com.android.settings.core.BasePreferenceController;
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+
|
||||
+public class BluetoothTimeoutPreferenceController extends BasePreferenceController implements
|
||||
+ PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||
+ private static final String TAG = "BluetoothTimeoutPrefCtrl";
|
||||
+
|
||||
+ public static final int FALLBACK_BLUETOOTH_TIMEOUT_VALUE = 0;
|
||||
+
|
||||
+ private final String mBluetoothTimeoutKey;
|
||||
+
|
||||
+ protected BluetoothAdapter mBluetoothAdapter;
|
||||
+
|
||||
+ public BluetoothTimeoutPreferenceController(Context context, String key) {
|
||||
+ super(context, key);
|
||||
+ mBluetoothTimeoutKey = key;
|
||||
+
|
||||
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
+ if (mBluetoothAdapter == null) {
|
||||
+ Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getAvailabilityStatus() {
|
||||
+ return mBluetoothAdapter != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return mBluetoothTimeoutKey;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateState(Preference preference) {
|
||||
+ final ListPreference timeoutListPreference = (ListPreference) preference;
|
||||
+ final long currentTimeout = Settings.Global.getLong(mContext.getContentResolver(),
|
||||
+ Settings.Global.BLUETOOTH_OFF_TIMEOUT, FALLBACK_BLUETOOTH_TIMEOUT_VALUE);
|
||||
+ timeoutListPreference.setValue(String.valueOf(currentTimeout));
|
||||
+ updateTimeoutPreferenceDescription(timeoutListPreference,
|
||||
+ Long.parseLong(timeoutListPreference.getValue()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
+ try {
|
||||
+ long value = Long.parseLong((String) newValue);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.BLUETOOTH_OFF_TIMEOUT, value);
|
||||
+ updateTimeoutPreferenceDescription((ListPreference) preference, value);
|
||||
+ } catch (NumberFormatException e) {
|
||||
+ Log.e(TAG, "could not persist bluetooth timeout setting", e);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public static CharSequence getTimeoutDescription(
|
||||
+ long currentTimeout, CharSequence[] entries, CharSequence[] values) {
|
||||
+ if (currentTimeout < 0 || entries == null || values == null
|
||||
+ || values.length != entries.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < values.length; i++) {
|
||||
+ long timeout = Long.parseLong(values[i].toString());
|
||||
+ if (currentTimeout == timeout) {
|
||||
+ return entries[i];
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private void updateTimeoutPreferenceDescription(ListPreference preference,
|
||||
+ long currentTimeout) {
|
||||
+ final CharSequence[] entries = preference.getEntries();
|
||||
+ final CharSequence[] values = preference.getEntryValues();
|
||||
+ final CharSequence timeoutDescription = getTimeoutDescription(
|
||||
+ currentTimeout, entries, values);
|
||||
+ String summary = "";
|
||||
+ if (timeoutDescription != null) {
|
||||
+ if (currentTimeout != 0)
|
||||
+ summary = mContext.getString(R.string.bluetooth_timeout_summary, timeoutDescription);
|
||||
+ else
|
||||
+ summary = mContext.getString(R.string.bluetooth_timeout_summary2);
|
||||
+ }
|
||||
+ preference.setSummary(summary);
|
||||
+ }
|
||||
+}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Oliver Scott <olivercscott@gmail.com>
|
||||
Date: Thu, 25 Feb 2021 11:31:14 -0500
|
||||
Subject: [PATCH] add Wi-Fi timeout feature
|
||||
|
||||
---
|
||||
res/values/arrays.xml | 44 +++++++
|
||||
res/values/strings.xml | 19 +++
|
||||
res/xml/wifi_configure_settings.xml | 8 ++
|
||||
.../wifi/WifiTimeoutPreferenceController.java | 115 ++++++++++++++++++
|
||||
4 files changed, 186 insertions(+)
|
||||
create mode 100644 src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
|
||||
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
|
||||
index 1a2796ad276..9344280a905 100644
|
||||
--- a/res/values/arrays.xml
|
||||
+++ b/res/values/arrays.xml
|
||||
@@ -62,6 +62,50 @@
|
||||
<item>28800000</item>
|
||||
</string-array>
|
||||
|
||||
+ <!-- Wifi settings. The delay in inactivity before wifi is turned off. These are shown in a list dialog. -->
|
||||
+ <string-array name="wifi_timeout_entries">
|
||||
+ <item>@string/wifi_timeout_summary_never</item>
|
||||
+ <item>@string/wifi_timeout_summary_15secs</item>
|
||||
+ <item>@string/wifi_timeout_summary_30secs</item>
|
||||
+ <item>@string/wifi_timeout_summary_1min</item>
|
||||
+ <item>@string/wifi_timeout_summary_2mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_5mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_10mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_30mins</item>
|
||||
+ <item>@string/wifi_timeout_summary_1hour</item>
|
||||
+ <item>@string/wifi_timeout_summary_2hours</item>
|
||||
+ <item>@string/wifi_timeout_summary_4hours</item>
|
||||
+ <item>@string/wifi_timeout_summary_8hours</item>
|
||||
+ </string-array>
|
||||
+
|
||||
+ <!-- Do not translate. -->
|
||||
+ <string-array name="wifi_timeout_values" translatable="false">
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>0</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>15000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>30000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>60000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>120000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>300000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>1800000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>3600000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>7200000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>14400000</item>
|
||||
+ <!-- Do not translate. -->
|
||||
+ <item>28800000</item>
|
||||
+ </string-array>
|
||||
+
|
||||
<!-- Display settings. The delay in inactivity before the screen is turned off. These are shown in a list dialog. -->
|
||||
<string-array name="screen_timeout_entries">
|
||||
<item>15 seconds</item>
|
||||
diff --git a/res/values/strings.xml b/res/values/strings.xml
|
||||
index cf41793fd42..1c3f864c956 100644
|
||||
--- a/res/values/strings.xml
|
||||
+++ b/res/values/strings.xml
|
||||
@@ -46,6 +46,25 @@
|
||||
<string name="bluetooth_timeout_summary_4hours">4 hours</string>
|
||||
<string name="bluetooth_timeout_summary_8hours">8 hours</string>
|
||||
|
||||
+ <!-- screen, setting option name to change wifi timeout -->
|
||||
+ <string name="wifi_timeout">Turn off Wi-Fi automatically</string>
|
||||
+
|
||||
+ <!-- screen, setting option summary to change wifi timeout -->
|
||||
+ <string name="wifi_timeout_summary">Wi-Fi will turn off after <xliff:g id="timeout_description">%1$s</xliff:g> if no network connected</string>
|
||||
+ <string name="wifi_timeout_summary2">Disabled</string>
|
||||
+ <string name="wifi_timeout_summary_never">Never</string>
|
||||
+ <string name="wifi_timeout_summary_15secs">15 seconds</string>
|
||||
+ <string name="wifi_timeout_summary_30secs">30 seconds</string>
|
||||
+ <string name="wifi_timeout_summary_1min">1 minute</string>
|
||||
+ <string name="wifi_timeout_summary_2mins">2 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_5mins">5 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_10mins">10 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_30mins">30 minutes</string>
|
||||
+ <string name="wifi_timeout_summary_1hour">1 hour</string>
|
||||
+ <string name="wifi_timeout_summary_2hours">2 hours</string>
|
||||
+ <string name="wifi_timeout_summary_4hours">4 hours</string>
|
||||
+ <string name="wifi_timeout_summary_8hours">8 hours</string>
|
||||
+
|
||||
<!-- Device Info screen. Used for a status item's value when the proper value is not known -->
|
||||
<string name="device_info_default">Unknown</string>
|
||||
<!-- String for removal of sensitive info on about, depending on tap -->
|
||||
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
|
||||
index 5866c5898d9..663e3109d76 100644
|
||||
--- a/res/xml/wifi_configure_settings.xml
|
||||
+++ b/res/xml/wifi_configure_settings.xml
|
||||
@@ -26,6 +26,14 @@
|
||||
android:summary="@string/wifi_wakeup_summary"
|
||||
settings:controller="com.android.settings.wifi.WifiWakeupPreferenceController"/>
|
||||
|
||||
+ <ListPreference
|
||||
+ android:key="wifi_timeout"
|
||||
+ android:title="@string/wifi_timeout"
|
||||
+ android:summary="@string/wifi_timeout_summary"
|
||||
+ android:entries="@array/wifi_timeout_entries"
|
||||
+ android:entryValues="@array/wifi_timeout_values"
|
||||
+ settings:controller="com.android.settings.wifi.WifiTimeoutPreferenceController"/>
|
||||
+
|
||||
<SwitchPreferenceCompat
|
||||
android:key="notify_open_networks"
|
||||
android:title="@string/wifi_notify_open_networks"
|
||||
diff --git a/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java b/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
new file mode 100644
|
||||
index 00000000000..7116c905190
|
||||
--- /dev/null
|
||||
+++ b/src/com/android/settings/wifi/WifiTimeoutPreferenceController.java
|
||||
@@ -0,0 +1,115 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2020 The Calyx Institute
|
||||
+ *
|
||||
+ * 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.wifi;
|
||||
+
|
||||
+import android.content.Context;
|
||||
+import android.net.wifi.WifiManager;
|
||||
+import android.provider.Settings;
|
||||
+import android.util.Log;
|
||||
+
|
||||
+import androidx.preference.ListPreference;
|
||||
+import androidx.preference.Preference;
|
||||
+
|
||||
+import com.android.settings.R;
|
||||
+import com.android.settings.core.BasePreferenceController;
|
||||
+import com.android.settings.core.PreferenceControllerMixin;
|
||||
+
|
||||
+public class WifiTimeoutPreferenceController extends BasePreferenceController implements
|
||||
+ PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
|
||||
+ private static final String TAG = "WifiTimeoutPrefCtrl";
|
||||
+
|
||||
+ public static final int FALLBACK_WIFI_TIMEOUT_VALUE = 0;
|
||||
+
|
||||
+ private final String mWifiTimeoutKey;
|
||||
+
|
||||
+ protected WifiManager mWifiManager;
|
||||
+
|
||||
+ public WifiTimeoutPreferenceController(Context context, String key) {
|
||||
+ super(context, key);
|
||||
+ mWifiTimeoutKey = key;
|
||||
+
|
||||
+ mWifiManager = context.getSystemService(WifiManager.class);
|
||||
+ if (mWifiManager == null) {
|
||||
+ Log.e(TAG, "Wifi is not supported on this device");
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getAvailabilityStatus() {
|
||||
+ return mWifiManager != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String getPreferenceKey() {
|
||||
+ return mWifiTimeoutKey;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void updateState(Preference preference) {
|
||||
+ final ListPreference timeoutListPreference = (ListPreference) preference;
|
||||
+ final long currentTimeout = Settings.Global.getLong(mContext.getContentResolver(),
|
||||
+ Settings.Global.WIFI_OFF_TIMEOUT, FALLBACK_WIFI_TIMEOUT_VALUE);
|
||||
+ timeoutListPreference.setValue(String.valueOf(currentTimeout));
|
||||
+ updateTimeoutPreferenceDescription(timeoutListPreference,
|
||||
+ Long.parseLong(timeoutListPreference.getValue()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
+ try {
|
||||
+ long value = Long.parseLong((String) newValue);
|
||||
+ Settings.Global.putLong(mContext.getContentResolver(), Settings.Global.WIFI_OFF_TIMEOUT, value);
|
||||
+ updateTimeoutPreferenceDescription((ListPreference) preference, value);
|
||||
+ } catch (NumberFormatException e) {
|
||||
+ Log.e(TAG, "could not persist wifi timeout setting", e);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public static CharSequence getTimeoutDescription(
|
||||
+ long currentTimeout, CharSequence[] entries, CharSequence[] values) {
|
||||
+ if (currentTimeout < 0 || entries == null || values == null
|
||||
+ || values.length != entries.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < values.length; i++) {
|
||||
+ long timeout = Long.parseLong(values[i].toString());
|
||||
+ if (currentTimeout == timeout) {
|
||||
+ return entries[i];
|
||||
+ }
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ private void updateTimeoutPreferenceDescription(ListPreference preference,
|
||||
+ long currentTimeout) {
|
||||
+ final CharSequence[] entries = preference.getEntries();
|
||||
+ final CharSequence[] values = preference.getEntryValues();
|
||||
+ final CharSequence timeoutDescription = getTimeoutDescription(
|
||||
+ currentTimeout, entries, values);
|
||||
+ String summary = "";
|
||||
+ if (timeoutDescription != null) {
|
||||
+ if (currentTimeout != 0)
|
||||
+ summary = mContext.getString(R.string.wifi_timeout_summary, timeoutDescription);
|
||||
+ else
|
||||
+ summary = mContext.getString(R.string.wifi_timeout_summary2);
|
||||
+ }
|
||||
+ preference.setSummary(summary);
|
||||
+ }
|
||||
+}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Port AXP auto-reboot, Wi-Fi/Bluetooth timeouts, and sensitive QS tiles.
|
||||
|
||||
AXP Patch.sh order @ 7b735844, applied with --fuzz=0:
|
||||
0014-Automatic_Reboot.patch
|
||||
0015-System_Server_Extensions.patch
|
||||
0015-WiFi_Timeout.patch
|
||||
0015-Bluetooth_Timeout.patch
|
||||
0015-Bluetooth_Timeout-Fix.patch
|
||||
0041-tile_restrictions.patch
|
||||
|
||||
A16 adaptations after the exact hunks:
|
||||
* privapp-permissions gained READ_SYSTEM_GRAMMATICAL_GENDER, so the REBOOT
|
||||
line is inserted between REAL_GET_TASKS and REQUEST_NETWORK_SCORES.
|
||||
* onKeyguardExitFinished() now dismisses the keyguard interactor before the
|
||||
closing brace. The AXP cancel stays immediately after sendUserPresentBroadcast().
|
||||
* QSTileImpl no longer imports QsInCompose, so KeyguardStateController is
|
||||
imported after QSLogger.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
PATCH_DIR = pathlib.Path(__file__).resolve().parent / "a15-src" / "frameworks_base"
|
||||
BASE = TREE / "frameworks/base"
|
||||
|
||||
XML = BASE / "data/etc/com.android.systemui.xml"
|
||||
KEYGUARD = (
|
||||
BASE / "packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java"
|
||||
)
|
||||
QSTILE = BASE / "packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java"
|
||||
|
||||
XML_OLD = """ <permission name="android.permission.REAL_GET_TASKS"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
"""
|
||||
XML_NEW = """ <permission name="android.permission.REAL_GET_TASKS"/>
|
||||
<permission name="android.permission.REBOOT"/>
|
||||
<permission name="android.permission.REQUEST_NETWORK_SCORES"/>
|
||||
"""
|
||||
|
||||
KEYGUARD_OLD = """ adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
|
||||
if (!KeyguardWmStateRefactor.isEnabled()) {
|
||||
mKeyguardInteractor.dismissKeyguard();
|
||||
}
|
||||
"""
|
||||
KEYGUARD_NEW = """ adjustStatusBarLocked();
|
||||
sendUserPresentBroadcast();
|
||||
cancelDoRebootForOwnerAfterTimeoutIfEnabled();
|
||||
|
||||
if (!KeyguardWmStateRefactor.isEnabled()) {
|
||||
mKeyguardInteractor.dismissKeyguard();
|
||||
}
|
||||
"""
|
||||
|
||||
IMPORT_OLD = "import com.android.systemui.qs.logging.QSLogger;\n"
|
||||
IMPORT_NEW = (
|
||||
"import com.android.systemui.qs.logging.QSLogger;\n"
|
||||
"import com.android.systemui.statusbar.policy.KeyguardStateController;\n"
|
||||
)
|
||||
|
||||
|
||||
def replace_once(path: pathlib.Path, old: str, new: str) -> None:
|
||||
text = path.read_text()
|
||||
if new in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def apply_patch(name: str) -> None:
|
||||
patch = PATCH_DIR / name
|
||||
if not patch.is_file():
|
||||
sys.exit(f"missing {patch}")
|
||||
result = subprocess.run(
|
||||
[
|
||||
"patch",
|
||||
"-p1",
|
||||
"--forward",
|
||||
"--fuzz=0",
|
||||
"--batch",
|
||||
"--no-backup-if-mismatch",
|
||||
"-d",
|
||||
str(BASE),
|
||||
"-i",
|
||||
str(patch),
|
||||
],
|
||||
check=False,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
)
|
||||
sys.stdout.write(result.stdout)
|
||||
sys.stdout.write(result.stderr)
|
||||
if result.returncode != 0 and "FAILED" in result.stderr + result.stdout:
|
||||
print(f"patch_incomplete: {name}")
|
||||
elif result.returncode != 0:
|
||||
print(f"patch_exit_{result.returncode}: {name}")
|
||||
|
||||
|
||||
def clean_rejects() -> None:
|
||||
for path in (XML, KEYGUARD, QSTILE):
|
||||
for suffix in (".rej", ".orig"):
|
||||
extra = path.with_name(path.name + suffix)
|
||||
if extra.exists():
|
||||
extra.unlink()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
apply_patch("0014-Automatic_Reboot.patch")
|
||||
replace_once(XML, XML_OLD, XML_NEW)
|
||||
replace_once(KEYGUARD, KEYGUARD_OLD, KEYGUARD_NEW)
|
||||
for name in (
|
||||
"0015-System_Server_Extensions.patch",
|
||||
"0015-WiFi_Timeout.patch",
|
||||
"0015-Bluetooth_Timeout.patch",
|
||||
"0015-Bluetooth_Timeout-Fix.patch",
|
||||
"0041-tile_restrictions.patch",
|
||||
):
|
||||
apply_patch(name)
|
||||
replace_once(QSTILE, IMPORT_OLD, IMPORT_NEW)
|
||||
clean_rejects()
|
||||
required = [
|
||||
"settings_reboot_after_timeout",
|
||||
"android.permission.REBOOT",
|
||||
"cancelDoRebootForOwnerAfterTimeoutIfEnabled();",
|
||||
"class SystemServerExt",
|
||||
"class WifiAutoOff",
|
||||
"class BluetoothAutoOff",
|
||||
"import android.bluetooth.BluetoothProfile;",
|
||||
"WIFI_OFF_TIMEOUT",
|
||||
"BLUETOOTH_OFF_TIMEOUT",
|
||||
"isAllowedWhenLocked",
|
||||
"KeyguardStateController",
|
||||
]
|
||||
blob = "\n".join(
|
||||
path.read_text()
|
||||
for path in (
|
||||
BASE / "core/java/android/provider/Settings.java",
|
||||
XML,
|
||||
KEYGUARD,
|
||||
BASE / "services/core/java/com/android/server/ext/SystemServerExt.java",
|
||||
BASE / "services/core/java/com/android/server/ext/WifiAutoOff.java",
|
||||
BASE / "services/core/java/com/android/server/ext/BluetoothAutoOff.java",
|
||||
QSTILE,
|
||||
)
|
||||
)
|
||||
missing = [item for item in required if item not in blob]
|
||||
if missing:
|
||||
sys.exit("missing after apply: " + ", ".join(missing))
|
||||
print("done: SUNFISH_A16_009_A15_REBOOT_TIMEOUTS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Settings UI for the AXP reboot and radio timeouts.
|
||||
|
||||
Apply after apply_009_a15_reboot_timeouts.py. Order matches AXP:
|
||||
bluetooth arrays land before the Wi-Fi arrays, which insert after them.
|
||||
|
||||
0006 needs fuzz 2. A16's strings.xml has an empty line where the A15
|
||||
patch has a single space, and connected_devices.xml shifted by a few
|
||||
lines. The preference still lands on the connected-devices screen.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
PATCH_DIR = pathlib.Path(__file__).resolve().parent / "a15-src" / "settings"
|
||||
SETTINGS = TREE / "packages/apps/Settings"
|
||||
|
||||
|
||||
MARKERS = (
|
||||
"res/xml/security_dashboard_settings.xml",
|
||||
"res/xml/connected_devices.xml",
|
||||
"res/xml/wifi_configure_settings.xml",
|
||||
"res/values/arrays.xml",
|
||||
"res/values/strings.xml",
|
||||
)
|
||||
|
||||
|
||||
def already_applied() -> bool:
|
||||
try:
|
||||
blob = "\n".join((SETTINGS / name).read_text() for name in MARKERS)
|
||||
except OSError:
|
||||
return False
|
||||
needles = (
|
||||
'android:key="auto_reboot"',
|
||||
'android:key="bluetooth_timeout"',
|
||||
'android:key="wifi_timeout"',
|
||||
'name="auto_reboot_entries"',
|
||||
'name="bluetooth_timeout_entries"',
|
||||
'name="wifi_timeout_entries"',
|
||||
)
|
||||
return all(needle in blob for needle in needles)
|
||||
|
||||
|
||||
def apply_patch(name: str, fuzz: str) -> None:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"patch",
|
||||
"-p1",
|
||||
"--forward",
|
||||
f"--fuzz={fuzz}",
|
||||
"--batch",
|
||||
"--no-backup-if-mismatch",
|
||||
"-d",
|
||||
str(SETTINGS),
|
||||
"-i",
|
||||
str(PATCH_DIR / name),
|
||||
],
|
||||
check=False,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
)
|
||||
sys.stdout.write(result.stdout)
|
||||
sys.stdout.write(result.stderr)
|
||||
for path in SETTINGS.rglob("*.rej"):
|
||||
path.unlink()
|
||||
if "FAILED" in result.stdout + result.stderr and not already_applied():
|
||||
sys.exit(f"failed: {name}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if already_applied():
|
||||
print("done: SUNFISH_A16_009_A15_SETTINGS_TIMEOUTS")
|
||||
return
|
||||
apply_patch("0005-Automatic_Reboot.patch", "0")
|
||||
apply_patch("0006-Bluetooth_Timeout.patch", "2")
|
||||
apply_patch("0007-WiFi_Timeout.patch", "0")
|
||||
if not already_applied():
|
||||
sys.exit("missing settings timeout markers")
|
||||
print("done: SUNFISH_A16_009_A15_SETTINGS_TIMEOUTS")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Port four AXP LOS 22.2 userspace changes onto LOS 23 / Android 16.
|
||||
|
||||
Sources, Patch.sh @ 7b735844 (AXP A15):
|
||||
android_frameworks_base/0004-Fingerprint_Lockout.patch
|
||||
android_frameworks_base/0007-Always_Restict_Serial.patch
|
||||
android_frameworks_base/0042-minimal_screenshot_exif.patch
|
||||
android_bootable_recovery/0001-No_SerialNum_Restrictions.patch
|
||||
|
||||
Sunfish fingerprint HAL is HIDL 2.2, and HidlToAidlSensorAdapter still uses
|
||||
LockoutFrameworkImpl, so the AXP constant change is the live path.
|
||||
|
||||
A16 adaptations, behavior unchanged:
|
||||
* CheckPackageMetadata returns bool, so a serial constraint returns false.
|
||||
The A15 patch returned INSTALL_ERROR, which does not compile here.
|
||||
* Screenshot EXIF drops the now-unused Build and DateTimeFormatter imports.
|
||||
A16 ErrorProne treats unused imports as errors.
|
||||
|
||||
Already satisfied on this tree, so this script does not touch them:
|
||||
* 0028-Remove_Legacy_Package_Query: A16 already removed the
|
||||
MATCH_UNINSTALLED_PACKAGES / MATCH_ANY_USER branch.
|
||||
* system/core 0002-ptrace_scope: apply_009_yama_ptrace.py already writes
|
||||
persist.native_debug.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("SUNFISH_A16_TREE", "/srv/rom/src/lineage"))
|
||||
|
||||
LOCKOUT = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/biometrics"
|
||||
/ "sensors/fingerprint/hidl/LockoutFrameworkImpl.java"
|
||||
)
|
||||
AMS = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/am"
|
||||
/ "ActivityManagerService.java"
|
||||
)
|
||||
EXIF = (
|
||||
TREE
|
||||
/ "frameworks/base/packages/SystemUI/src/com/android/systemui"
|
||||
/ "screenshot/ImageExporter.java"
|
||||
)
|
||||
RECOVERY = TREE / "bootable/recovery/install/install.cpp"
|
||||
|
||||
LOCKOUT_OLD = "private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;"
|
||||
LOCKOUT_NEW = "private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 5;"
|
||||
|
||||
SERIAL_OLD = """ // We deprecated Build.SERIAL and it is not accessible to
|
||||
// Instant Apps and target APIs higher than O MR1. Since access to the serial
|
||||
// is now behind a permission we push down the value.
|
||||
final String buildSerial = (!appInfo.isInstantApp()
|
||||
&& appInfo.targetSdkVersion < Build.VERSION_CODES.P)
|
||||
? sTheRealBuildSerial : Build.UNKNOWN;
|
||||
"""
|
||||
SERIAL_NEW = """ // AXP/GrapheneOS 0007: deprecated Build.SERIAL stays UNKNOWN.
|
||||
// Callers use Build.getSerial(), which requires READ_PHONE_STATE.
|
||||
final String buildSerial = Build.UNKNOWN;
|
||||
"""
|
||||
|
||||
EXIF_OLD = """ exif.setAttribute(ExifInterface.TAG_IMAGE_UNIQUE_ID, uniqueId.toString());
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY);
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
|
||||
|
||||
String dateTime = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(captureTime);
|
||||
String subSec = DateTimeFormatter.ofPattern("SSS").format(captureTime);
|
||||
String timeZone = DateTimeFormatter.ofPattern("xxx").format(captureTime);
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTime);
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, subSec);
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, timeZone);
|
||||
"""
|
||||
EXIF_NEW = """ // AXP/Calyx 0042: width and height only. No OS name, unique id, or time.
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
|
||||
"""
|
||||
|
||||
RECOVERY_OLD = """ // We allow the package to not have any serialno; and we also allow it to carry multiple serial
|
||||
// numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the
|
||||
// verification if the device's serialno doesn't match any of these carried numbers.
|
||||
|
||||
auto pkg_serial_no = get_value(metadata, "serialno");
|
||||
if (!pkg_serial_no.empty()) {
|
||||
auto device_serial_no = android::base::GetProperty("ro.serialno", "");
|
||||
bool serial_number_match = false;
|
||||
for (const auto& number : android::base::Split(pkg_serial_no, "|")) {
|
||||
if (device_serial_no == android::base::Trim(number)) {
|
||||
serial_number_match = true;
|
||||
}
|
||||
}
|
||||
if (!serial_number_match) {
|
||||
LOG(ERROR) << "Package is for serial " << pkg_serial_no;
|
||||
return false;
|
||||
}
|
||||
} else if (ota_type == OtaType::BRICK) {
|
||||
"""
|
||||
RECOVERY_NEW = """ // AXP/GrapheneOS 0001: any serialno constraint is rejected.
|
||||
// A16 CheckPackageMetadata returns bool; A15 returned INSTALL_ERROR.
|
||||
auto pkg_serial_no = get_value(metadata, "serialno");
|
||||
if (!pkg_serial_no.empty()) {
|
||||
LOG(ERROR) << "Serial number constraint not permitted: " << pkg_serial_no;
|
||||
return false;
|
||||
} else if (ota_type == OtaType::BRICK) {
|
||||
"""
|
||||
|
||||
|
||||
def replace_once(path: pathlib.Path, old: str, new: str) -> None:
|
||||
text = path.read_text()
|
||||
if new in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def drop_import(text: str, import_line: str, still_used: str) -> str:
|
||||
if import_line not in text:
|
||||
return text
|
||||
body = text.replace(import_line + "\n", "", 1)
|
||||
if still_used in body:
|
||||
return text
|
||||
return body
|
||||
|
||||
|
||||
def apply_exif() -> None:
|
||||
text = EXIF.read_text()
|
||||
if EXIF_NEW in text:
|
||||
updated = text
|
||||
elif EXIF_OLD not in text:
|
||||
sys.exit(f"anchor missing in {EXIF}")
|
||||
else:
|
||||
updated = text.replace(EXIF_OLD, EXIF_NEW, 1)
|
||||
updated = drop_import(updated, "import android.os.Build;", "Build.")
|
||||
updated = drop_import(
|
||||
updated, "import java.time.format.DateTimeFormatter;", "DateTimeFormatter"
|
||||
)
|
||||
EXIF.write_text(updated)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
replace_once(LOCKOUT, LOCKOUT_OLD, LOCKOUT_NEW)
|
||||
replace_once(AMS, SERIAL_OLD, SERIAL_NEW)
|
||||
apply_exif()
|
||||
replace_once(RECOVERY, RECOVERY_OLD, RECOVERY_NEW)
|
||||
print("done: SUNFISH_A16_009_A15_SMALL")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: AXP ship identity on LOS 23.2.
|
||||
|
||||
- AXP Patch.sh (LineageOS-22.2:405) replaces LINEAGE_BUILDTYPE := UNOFFICIAL
|
||||
with its own build type in vendor/lineage/config/*.mk. Same here, with PRO
|
||||
(GOLDEN ro.lineage.releasetype=PRO).
|
||||
- Drops the old TARGET_UNOFFICIAL_BUILD_ID insert from lineage_sunfish.mk.
|
||||
- Vendor SPL stays the LOS 23.2 2023-09-05 (AXP GOLDEN ships 2023-08-05).
|
||||
- build/make/core/config.mk only tags release-keys when the default cert is
|
||||
under vendor/lineage-priv/. Copies the project certs there (same keys, so
|
||||
an existing install updates without a wipe).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
SRC_CERTS = TREE / "vendor/sunfish-a16/certs"
|
||||
DST_CERTS = TREE / "vendor/lineage-priv/keys"
|
||||
OLD_ID = (
|
||||
"# sunfish-a16: must precede vendor/lineage version.mk (via inherit below)\n"
|
||||
"TARGET_UNOFFICIAL_BUILD_ID := AXP-Resurection-Pro\n\n"
|
||||
)
|
||||
# LOS 23.2 writes 2023-09-05. AXP GOLDEN uses 2023-08-05, but keymaster key
|
||||
# blobs on an existing install are bound to the vendor patch level and refuse
|
||||
# a rollback: vdc cryptfs init_user0 fails and recovery asks for a wipe
|
||||
# (LAB 2026-10-07 17:15 build). Never lower the vendor SPL on an upgrade.
|
||||
VENDOR_SPL_LOS = (
|
||||
"# Set Vendor SPL to match platform\n"
|
||||
"VENDOR_SECURITY_PATCH = 2023-09-05\n"
|
||||
)
|
||||
VENDOR_SPL_ROLLBACK = (
|
||||
"# Stock sunfish vendor SPL (TQ3A.230805), same as AXP GOLDEN.\n"
|
||||
"# System PLATFORM_SECURITY_PATCH stays the LOS 23.2 ASB.\n"
|
||||
"VENDOR_SECURITY_PATCH = 2023-08-05\n"
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
version = TREE / "vendor/lineage/config/version.mk"
|
||||
text = version.read_text()
|
||||
if "LINEAGE_BUILDTYPE := PRO\n" not in text:
|
||||
old = " LINEAGE_BUILDTYPE := UNOFFICIAL\n"
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {version}")
|
||||
version.write_text(text.replace(old, " LINEAGE_BUILDTYPE := PRO\n", 1))
|
||||
|
||||
device_mk = TREE / "device/google/sunfish/lineage_sunfish.mk"
|
||||
text = device_mk.read_text()
|
||||
if OLD_ID in text:
|
||||
device_mk.write_text(text.replace(OLD_ID, "", 1))
|
||||
if "TARGET_UNOFFICIAL_BUILD_ID" in device_mk.read_text():
|
||||
sys.exit(f"TARGET_UNOFFICIAL_BUILD_ID still set in {device_mk}")
|
||||
|
||||
common = TREE / "device/google/sunfish/device-common.mk"
|
||||
text = common.read_text()
|
||||
if VENDOR_SPL_ROLLBACK in text:
|
||||
text = text.replace(VENDOR_SPL_ROLLBACK, VENDOR_SPL_LOS, 1)
|
||||
common.write_text(text)
|
||||
if VENDOR_SPL_LOS not in text:
|
||||
sys.exit(f"vendor SPL is not 2023-09-05 in {common}")
|
||||
|
||||
if not (SRC_CERTS / "releasekey.pk8").is_file():
|
||||
sys.exit(f"missing {SRC_CERTS}/releasekey.pk8")
|
||||
DST_CERTS.mkdir(parents=True, exist_ok=True)
|
||||
for src in SRC_CERTS.iterdir():
|
||||
if src.name.startswith("avb"):
|
||||
continue
|
||||
dst = DST_CERTS / src.name
|
||||
if dst.is_symlink() or dst.exists():
|
||||
dst.unlink()
|
||||
if src.is_symlink():
|
||||
dst.symlink_to(src.readlink())
|
||||
else:
|
||||
shutil.copy2(src, dst)
|
||||
print("axp identity applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Hide /proc/cmdline from unprivileged processes.
|
||||
|
||||
AOSP and GOLDEN's init do this in first-stage init, immediately after
|
||||
mounting proc:
|
||||
|
||||
CHECKCALL(chmod("/proc/cmdline", 0440));
|
||||
|
||||
The failure text is exactly `chmod("/proc/cmdline", 0440) failed`, which
|
||||
is present in GOLDEN's /system/bin/init and absent from the LOS 23.2 init
|
||||
that left the file mode 0444. LOS 23.2 already chmod's /proc/bootconfig
|
||||
the same way. init.rc only chowns cmdline to root:radio.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path(os.environ.get("ANDROID_BUILD_TOP", "/srv/rom/src/lineage"))
|
||||
INIT = TREE / "system/core/init/first_stage_init.cpp"
|
||||
OLD = """#undef MAKE_STR
|
||||
std::string cmdline;
|
||||
android::base::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
"""
|
||||
NEW = """#undef MAKE_STR
|
||||
// Don't expose the raw commandline to unprivileged processes.
|
||||
CHECKCALL(chmod("/proc/cmdline", 0440));
|
||||
std::string cmdline;
|
||||
android::base::ReadFileToString("/proc/cmdline", &cmdline);
|
||||
"""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
text = INIT.read_text()
|
||||
if NEW in text:
|
||||
print(f"already applied: {INIT}")
|
||||
return
|
||||
if OLD not in text:
|
||||
sys.exit(f"cmdline chmod anchor missing in {INIT}")
|
||||
INIT.write_text(text.replace(OLD, NEW, 1))
|
||||
print(f"patched cmdline mode: {INIT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop Google carrier apps and the AOSP IMS entitlement/RCS packages.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so a filter-out never
|
||||
sees names added by sunfish-vendor.mk. Remove the package lines where they
|
||||
are added. CarrierSettings/*.pb copy rules stay: their tokens are paths, not
|
||||
the CarrierSettings module. Qualcomm radio packages stay (ims, atfwd,
|
||||
qcrilmsgtunnel, uceShimService, EuiccSupportPixel).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGETS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/google/sunfish/sunfish-vendor.mk",
|
||||
(
|
||||
"CarrierServices",
|
||||
"CarrierSettings",
|
||||
"CarrierWifi",
|
||||
"CarrierSetup",
|
||||
"RilConfigService",
|
||||
"grilservice",
|
||||
),
|
||||
(
|
||||
"EuiccSupportPixel",
|
||||
"EuiccSupportPixelPermissions",
|
||||
"ims",
|
||||
"QtiTelephonyService",
|
||||
"atfwd",
|
||||
"qcrilmsgtunnel",
|
||||
"uceShimService",
|
||||
),
|
||||
),
|
||||
(
|
||||
"device/google/sunfish/device-lineage.mk",
|
||||
("PresencePolling", "RcsService"),
|
||||
("GoogleParts",),
|
||||
),
|
||||
(
|
||||
"build/make/target/product/telephony_product.mk",
|
||||
("ImsServiceEntitlement",),
|
||||
("Dialer",),
|
||||
),
|
||||
)
|
||||
|
||||
_RCS_STUB = "# RCS\nPRODUCT_PACKAGES += \\\n\n"
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def apply_file(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
token = _token(line)
|
||||
if token in removed:
|
||||
removed[token] += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if all(count == 0 for count in removed.values()):
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
new = "".join(kept)
|
||||
if path.name == "device-lineage.mk":
|
||||
new = new.replace(_RCS_STUB, "", 1)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in TARGETS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
state = apply_file(path, packages, keep)
|
||||
results.append(f"{state} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop the Google eUICC LPA from the sunfish vendor makefile.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so a filter-out in
|
||||
apps.mk never sees the names added by sunfish-vendor.mk. A Soong phony
|
||||
does not set PACKAGES.*.OVERRIDES. The 20261009T073753Z and 20261009T090831Z
|
||||
zips still installed both APKs. Remove the two entries where they are added.
|
||||
EuiccSupportPixel and EuiccSupportPixelPermissions stay.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
PACKAGES = ("EuiccGoogle", "EuiccGoogleOverlay")
|
||||
KEEP = ("EuiccSupportPixel", "EuiccSupportPixelPermissions")
|
||||
|
||||
|
||||
def _package_line(line: str) -> str | None:
|
||||
stripped = line.strip().rstrip("\\").strip()
|
||||
if stripped in PACKAGES:
|
||||
return stripped
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
mk = top / "vendor/google/sunfish/sunfish-vendor.mk"
|
||||
if not mk.is_file():
|
||||
print(f"FAIL: missing {mk}", file=sys.stderr)
|
||||
return 1
|
||||
text = mk.read_text()
|
||||
for name in KEEP:
|
||||
if name not in text:
|
||||
print(f"FAIL: {mk} lost {name}", file=sys.stderr)
|
||||
return 1
|
||||
removed = {name: 0 for name in PACKAGES}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
hit = _package_line(line)
|
||||
if hit is None:
|
||||
kept.append(line)
|
||||
continue
|
||||
removed[hit] += 1
|
||||
if all(count == 0 for count in removed.values()):
|
||||
print(f"OK: already applied ({mk})")
|
||||
return 0
|
||||
if any(count != 1 for count in removed.values()):
|
||||
print(f"FAIL: unexpected removals {removed}", file=sys.stderr)
|
||||
return 1
|
||||
new = "".join(kept)
|
||||
for name in KEEP:
|
||||
if name not in new:
|
||||
print(f"FAIL: edit would drop {name}", file=sys.stderr)
|
||||
return 1
|
||||
for name in PACKAGES:
|
||||
if f" {name} \\" in new or f" {name}\n" in new:
|
||||
print(f"FAIL: {name} still listed", file=sys.stderr)
|
||||
return 1
|
||||
mk.write_text(new)
|
||||
print(f"OK: dropped {', '.join(PACKAGES)} from {mk}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop commands present on LAB and absent on GOLDEN.
|
||||
|
||||
Keeps the GPS binaries loc_launcher, lowi-server and xtra-daemon.
|
||||
bpftool, alloctop and apexd-lsof.sh are not product packages: bpfloader,
|
||||
dumpstate and apexd require them. Remove only those required entries.
|
||||
pbtombstone stays in PRODUCT_HOST_PACKAGES; only the system copy goes.
|
||||
Qualcomm diag binaries and imsrcsd go. imsdatadaemon and the other IMS
|
||||
call daemons stay.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MAKE_DROPS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/google/sunfish/sunfish-vendor.mk",
|
||||
(
|
||||
"cnss_diag",
|
||||
"diag_klog",
|
||||
"diag_mdlog",
|
||||
"diag_socket_log",
|
||||
"diag_uart_log",
|
||||
"ssr_diag",
|
||||
"test_diag",
|
||||
"imsrcsd",
|
||||
),
|
||||
(
|
||||
"loc_launcher",
|
||||
"lowi-server",
|
||||
"xtra-daemon",
|
||||
"cnss-daemon",
|
||||
"imsdatadaemon",
|
||||
"imsqmidaemon",
|
||||
"ims_rtp_daemon",
|
||||
),
|
||||
),
|
||||
(
|
||||
"device/google/sunfish/device-lineage.mk",
|
||||
("disable_configstore",),
|
||||
("chre_daemon_msm",),
|
||||
),
|
||||
)
|
||||
|
||||
HOST_SAFE = {"pbtombstone"}
|
||||
|
||||
BP_LINES: tuple[tuple[str, str], ...] = (
|
||||
("system/bpf/loader/Android.bp", '"bpftool",'),
|
||||
("frameworks/native/cmds/dumpstate/Android.bp", '"alloctop",'),
|
||||
("system/apex/apexd/Android.bp", 'required: ["apexd-lsof.sh"],'),
|
||||
)
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def _assignment(line: str, current: str | None) -> str | None:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("PRODUCT_HOST_PACKAGES") and "+=" in stripped:
|
||||
return "PRODUCT_HOST_PACKAGES"
|
||||
if stripped.startswith("PRODUCT_PACKAGES") and "+=" in stripped:
|
||||
return "PRODUCT_PACKAGES"
|
||||
return current
|
||||
|
||||
|
||||
def apply_make(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
rc_removed = 0
|
||||
kept: list[str] = []
|
||||
assignment: str | None = None
|
||||
for line in text.splitlines(keepends=True):
|
||||
assignment = _assignment(line, assignment)
|
||||
token = _token(line)
|
||||
if token in removed and not (token in HOST_SAFE and assignment == "PRODUCT_HOST_PACKAGES"):
|
||||
removed[token] += 1
|
||||
continue
|
||||
if "imsrcsd.rc:" in line:
|
||||
rc_removed += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
pending = [name for name, count in removed.items() if count == 0]
|
||||
if pending and any(count for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: partial removal in {path}: {removed}")
|
||||
if not any(count for count in removed.values()) and rc_removed == 0:
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
if "imsrcsd" in packages and rc_removed != 1:
|
||||
raise SystemExit(f"FAIL: imsrcsd.rc removals={rc_removed} in {path}")
|
||||
new = "".join(kept)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
if "imsrcsd.rc:" in new:
|
||||
raise SystemExit(f"FAIL: imsrcsd.rc still copied from {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def apply_pbtombstone(path: Path) -> str:
|
||||
text = path.read_text()
|
||||
if not _has(text, "logcat") or not _has(text, "fastboot"):
|
||||
raise SystemExit(f"FAIL: {path} lost logcat or fastboot")
|
||||
removed = 0
|
||||
kept: list[str] = []
|
||||
assignment: str | None = None
|
||||
for line in text.splitlines(keepends=True):
|
||||
assignment = _assignment(line, assignment)
|
||||
token = _token(line)
|
||||
if token == "pbtombstone" and assignment == "PRODUCT_PACKAGES":
|
||||
removed += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if removed == 0:
|
||||
if not any(
|
||||
_token(line) == "pbtombstone" and True
|
||||
for line in text.splitlines()
|
||||
):
|
||||
raise SystemExit(f"FAIL: {path} has no pbtombstone at all")
|
||||
return "already"
|
||||
if removed != 1:
|
||||
raise SystemExit(f"FAIL: pbtombstone system removals={removed}")
|
||||
new = "".join(kept)
|
||||
host_hits = 0
|
||||
assignment = None
|
||||
for line in new.splitlines():
|
||||
assignment = _assignment(line, assignment)
|
||||
if _token(line) == "pbtombstone" and assignment == "PRODUCT_HOST_PACKAGES":
|
||||
host_hits += 1
|
||||
if host_hits != 1:
|
||||
raise SystemExit(f"FAIL: host pbtombstone count={host_hits}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def apply_bp(path: Path, needle: str) -> str:
|
||||
text = path.read_text()
|
||||
hits = [line for line in text.splitlines() if line.strip() == needle]
|
||||
if not hits:
|
||||
return "already"
|
||||
if len(hits) != 1:
|
||||
raise SystemExit(f"FAIL: {needle} appears {len(hits)} times in {path}")
|
||||
new = "".join(
|
||||
line for line in text.splitlines(keepends=True) if line.strip() != needle
|
||||
)
|
||||
if needle in new:
|
||||
raise SystemExit(f"FAIL: {needle} still present in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in MAKE_DROPS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_make(path, packages, keep)} {rel}")
|
||||
pb = top / "build/make/target/product/base_system.mk"
|
||||
if not pb.is_file():
|
||||
print(f"FAIL: missing {pb}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_pbtombstone(pb)} {pb.relative_to(top)}")
|
||||
for rel, needle in BP_LINES:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_bp(path, needle)} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drop Lineage tools that AXP.OS PRO sunfish does not ship.
|
||||
|
||||
GOLDEN has no /system_ext/bin/{bash,htop,nano,unrar} and no
|
||||
/system/addon.d/50-lineage.sh. It does ship curl and vim, so those tokens
|
||||
stay. Qualcomm diag binaries are a separate change.
|
||||
|
||||
inherit-product merges PRODUCT_PACKAGES per makefile, so filter-out cannot
|
||||
remove names added here. Delete the exact package-token lines.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGETS: tuple[tuple[str, tuple[str, ...], tuple[str, ...]], ...] = (
|
||||
(
|
||||
"vendor/lineage/config/common.mk",
|
||||
("bash", "htop", "nano", "50-lineage.sh"),
|
||||
("curl", "getcap", "setcap", "vim", "nano_recovery"),
|
||||
),
|
||||
(
|
||||
"vendor/lineage/config/common_mobile_full.mk",
|
||||
("unrar",),
|
||||
("zstd",),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _token(line: str) -> str:
|
||||
return line.strip().rstrip("\\").strip()
|
||||
|
||||
|
||||
def _has(text: str, name: str) -> bool:
|
||||
return any(_token(line) == name for line in text.splitlines())
|
||||
|
||||
|
||||
def apply_file(path: Path, packages: tuple[str, ...], keep: tuple[str, ...]) -> str:
|
||||
text = path.read_text()
|
||||
for name in keep:
|
||||
if not _has(text, name):
|
||||
raise SystemExit(f"FAIL: {path} lost {name}")
|
||||
removed = {name: 0 for name in packages}
|
||||
kept: list[str] = []
|
||||
for line in text.splitlines(keepends=True):
|
||||
token = _token(line)
|
||||
if token in removed:
|
||||
removed[token] += 1
|
||||
continue
|
||||
kept.append(line)
|
||||
if all(count == 0 for count in removed.values()):
|
||||
return "already"
|
||||
if any(count != 1 for count in removed.values()):
|
||||
raise SystemExit(f"FAIL: unexpected removals in {path}: {removed}")
|
||||
new = "".join(kept)
|
||||
for name in keep:
|
||||
if not _has(new, name):
|
||||
raise SystemExit(f"FAIL: edit would drop {name} from {path}")
|
||||
for name in packages:
|
||||
if _has(new, name):
|
||||
raise SystemExit(f"FAIL: {name} still listed in {path}")
|
||||
path.write_text(new)
|
||||
return "dropped"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
top = Path(os.environ.get("ANDROID_BUILD_TOP", ".")).resolve()
|
||||
results: list[str] = []
|
||||
for rel, packages, keep in TARGETS:
|
||||
path = top / rel
|
||||
if not path.is_file():
|
||||
print(f"FAIL: missing {path}", file=sys.stderr)
|
||||
return 1
|
||||
results.append(f"{apply_file(path, packages, keep)} {rel}")
|
||||
print("OK: " + "; ".join(results))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,576 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: SUPL privacy, plus an optional stop for LPP / XTRA / IZat.
|
||||
|
||||
- Never send IMSI or MSISDN to a SUPL server (AXP/Divest), including emergency.
|
||||
LOS 23 already skips that outside an emergency call.
|
||||
- Settings toggle "Force disable SUPL", default off. On forces SUPL_MODE=0.
|
||||
- GNSS NTP in sunfish gps.conf: 2.android.pool.ntp.org.
|
||||
- Settings toggle "Stop extra location assistance", default off.
|
||||
Off keeps Lineage LPP, XTRA and IZat. On sets LPP_PROFILE=0 (LPPE is
|
||||
carried by that LPP session), skips the framework XTRA download, and
|
||||
stops loc_launcher. The vendor binaries stay on the image.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
MARKER = "sunfish-a16-009-supl-privacy"
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
|
||||
|
||||
def must(path: pathlib.Path, old: str, new: str, already: str) -> None:
|
||||
text = path.read_text()
|
||||
if already in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
settings = TREE / "frameworks/base/core/java/android/provider/Settings.java"
|
||||
gnss_cfg = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/location/gnss/GnssConfiguration.java"
|
||||
)
|
||||
gnss_prov = (
|
||||
TREE
|
||||
/ "frameworks/base/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java"
|
||||
)
|
||||
loc_xml = TREE / "packages/apps/Settings/res/xml/location_settings.xml"
|
||||
strings = TREE / "packages/apps/Settings/res/values/strings.xml"
|
||||
gps = TREE / "device/google/sunfish/gps.conf"
|
||||
init_rc = TREE / "device/google/sunfish/init.hardware.rc"
|
||||
controller = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/location/ForceDisableSuplPrefController.java"
|
||||
)
|
||||
|
||||
must(
|
||||
settings,
|
||||
""" public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
|
||||
""",
|
||||
""" public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
|
||||
|
||||
/**
|
||||
* Force disable Secure User Plane Location (SUPL), 0 or 1.
|
||||
* Default 0 keeps carrier SUPL. AXP/Graphene toggle, """
|
||||
+ MARKER
|
||||
+ """.
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FORCE_DISABLE_SUPL = "force_disable_supl";
|
||||
|
||||
/** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
""",
|
||||
already="FORCE_DISABLE_SUPL",
|
||||
)
|
||||
|
||||
must(
|
||||
settings,
|
||||
""" /** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
""",
|
||||
""" /** @hide */
|
||||
public static final int FORCE_DISABLE_SUPL_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* Stop LPP, the framework XTRA download, and loc_launcher
|
||||
* (xtra-daemon, lowi, IZat). 0 or 1. Default 0 keeps Lineage
|
||||
* assistance. Binaries stay installed. """
|
||||
+ MARKER
|
||||
+ """.
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String FORCE_DISABLE_LOCATION_ASSIST =
|
||||
"force_disable_location_assist";
|
||||
|
||||
/** @hide */
|
||||
public static final int FORCE_DISABLE_LOCATION_ASSIST_DEFAULT = 0;
|
||||
""",
|
||||
already="FORCE_DISABLE_LOCATION_ASSIST",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_cfg,
|
||||
"import android.os.SystemProperties;\n",
|
||||
"import android.os.SystemProperties;\nimport android.provider.Settings;\n",
|
||||
already="import android.provider.Settings;\n",
|
||||
)
|
||||
must(
|
||||
gnss_cfg,
|
||||
"import android.util.Log;\n",
|
||||
"import android.util.Log;\nimport android.util.Slog;\n",
|
||||
already="import android.util.Slog;\n",
|
||||
)
|
||||
must(
|
||||
gnss_cfg,
|
||||
""" loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_VENDOR_FILE);
|
||||
loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_SYSTEM_FILE);
|
||||
""",
|
||||
""" loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_VENDOR_FILE);
|
||||
loadPropertiesFromGpsDebugConfig(mProperties, DEBUG_PROPERTIES_SYSTEM_FILE);
|
||||
applyConfigOverrides(mContext, mProperties); /* """
|
||||
+ MARKER
|
||||
+ """ */
|
||||
""",
|
||||
already="applyConfigOverrides(mContext, mProperties)",
|
||||
)
|
||||
if "void applyConfigOverrides(" not in gnss_cfg.read_text():
|
||||
text = gnss_cfg.read_text()
|
||||
needle = " private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);\n"
|
||||
insert = needle + """
|
||||
/** """ + MARKER + """: optional SUPL off. Default leaves carrier SUPL_MODE. */
|
||||
private static void applyConfigOverrides(Context ctx, Properties props) {
|
||||
String key = Settings.Global.FORCE_DISABLE_SUPL;
|
||||
int def = Settings.Global.FORCE_DISABLE_SUPL_DEFAULT;
|
||||
if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
}
|
||||
"""
|
||||
if needle not in text:
|
||||
sys.exit("native_set_es_extension_sec missing")
|
||||
gnss_cfg.write_text(text.replace(needle, insert, 1))
|
||||
|
||||
must(
|
||||
gnss_cfg,
|
||||
""" if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
}
|
||||
""",
|
||||
""" if (Settings.Global.getInt(ctx.getContentResolver(), key, def) == 1) {
|
||||
props.setProperty(CONFIG_SUPL_MODE, "0");
|
||||
Slog.d(TAG, "SUPL is force disabled");
|
||||
}
|
||||
String assist = Settings.Global.FORCE_DISABLE_LOCATION_ASSIST;
|
||||
int assistDef = Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT;
|
||||
if (Settings.Global.getInt(ctx.getContentResolver(), assist, assistDef) == 1) {
|
||||
// LPPE is carried by the LPP session. This HAL only has a setter
|
||||
// for LPP_PROFILE, and this override runs after carrier config.
|
||||
props.setProperty(CONFIG_LPP_PROFILE, "0");
|
||||
Slog.d(TAG, "LPP assistance stopped");
|
||||
}
|
||||
}
|
||||
""",
|
||||
already="LPP assistance stopped",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ASSISTED_GPS_ENABLED),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
""" mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ASSISTED_GPS_ENABLED),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
|
||||
/* """
|
||||
+ MARKER
|
||||
+ """ */
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
already="Settings.Global.FORCE_DISABLE_SUPL",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
""" Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_SUPL),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.FORCE_DISABLE_LOCATION_ASSIST),
|
||||
false,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
reloadGpsProperties();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
""",
|
||||
already="Settings.Global.FORCE_DISABLE_LOCATION_ASSIST",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" toggleXtraDaemon();
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, GnssNative gnssNative,
|
||||
""",
|
||||
""" applyLocationAssistPrivacy();
|
||||
toggleXtraDaemon();
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, GnssNative gnssNative,
|
||||
""",
|
||||
already="applyLocationAssistPrivacy();",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" if (!isAssistedGpsEnabled()) {
|
||||
// PSDS download disabled by system setting, don't try
|
||||
Log.d(TAG, "handleDownloadPsdsData() called when PSDS disabled by system setting");
|
||||
return;
|
||||
}
|
||||
""",
|
||||
""" if (!isAssistedGpsEnabled()) {
|
||||
// PSDS download disabled by system setting, don't try
|
||||
Log.d(TAG, "handleDownloadPsdsData() called when PSDS disabled by system setting");
|
||||
return;
|
||||
}
|
||||
if (Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1) {
|
||||
Log.d(TAG, "handleDownloadPsdsData() skipped: location assistance stopped");
|
||||
return;
|
||||
}
|
||||
""",
|
||||
already="location assistance stopped",
|
||||
)
|
||||
|
||||
must(
|
||||
gnss_prov,
|
||||
""" private void toggleXtraDaemon() {
|
||||
Log.i(TAG, "Toggling xtra-daemon via property");
|
||||
SystemProperties.set("persist.sys.xtra-daemon.enabled",
|
||||
Boolean.toString(isAssistedGpsEnabled()));
|
||||
}
|
||||
""",
|
||||
""" /** """
|
||||
+ MARKER
|
||||
+ """ Stop loc_launcher. Does not delete xtra-daemon, lowi or IZat. */
|
||||
private void applyLocationAssistPrivacy() {
|
||||
boolean stop = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1;
|
||||
SystemProperties.set("persist.sys.axp.loc_privacy", stop ? "1" : "0");
|
||||
}
|
||||
|
||||
private void toggleXtraDaemon() {
|
||||
Log.i(TAG, "Toggling xtra-daemon via property");
|
||||
SystemProperties.set("persist.sys.xtra-daemon.enabled",
|
||||
Boolean.toString(isAssistedGpsEnabled()));
|
||||
}
|
||||
""",
|
||||
already="persist.sys.axp.loc_privacy",
|
||||
)
|
||||
|
||||
old_setid = """ TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
int type = AGPS_SETID_TYPE_NONE;
|
||||
String setId = null;
|
||||
final Boolean isEmergency = mNIHandler.getInEmergency();
|
||||
|
||||
// Unless we are in an emergency, do not provide sensitive subscriber information
|
||||
// to SUPL servers.
|
||||
if (!isEmergency) {
|
||||
mGnssNative.setAgpsSetId(type, "");
|
||||
return;
|
||||
}
|
||||
|
||||
int subId = SubscriptionManager.getDefaultDataSubscriptionId();
|
||||
if (mGnssConfiguration.isActiveSimEmergencySuplEnabled() && isEmergency
|
||||
&& mNetworkConnectivityHandler.getActiveSubId() >= 0) {
|
||||
subId = mNetworkConnectivityHandler.getActiveSubId();
|
||||
}
|
||||
if (SubscriptionManager.isValidSubscriptionId(subId)) {
|
||||
phone = phone.createForSubscriptionId(subId);
|
||||
}
|
||||
if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) {
|
||||
setId = phone.getSubscriberId();
|
||||
if (setId != null) {
|
||||
// This means the framework has the SIM card.
|
||||
type = AGPS_SETID_TYPE_IMSI;
|
||||
}
|
||||
} else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) {
|
||||
setId = phone.getLine1Number();
|
||||
if (setId != null) {
|
||||
// This means the framework has the SIM card.
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
}
|
||||
}
|
||||
|
||||
mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId);
|
||||
"""
|
||||
new_setid = """ // """ + MARKER + """: AXP/Divest. Never send IMSI or the phone number
|
||||
// to a SUPL server, including during an emergency call. LOS 23 already
|
||||
// skips this outside emergency. Control-plane A-GNSS is unchanged.
|
||||
// flags is read so the unused-parameter check stays quiet.
|
||||
if (flags != 0 && Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "ignoring SUPL set-id request flags=" + flags);
|
||||
}
|
||||
mGnssNative.setAgpsSetId(AGPS_SETID_TYPE_NONE, "");
|
||||
"""
|
||||
prov = gnss_prov.read_text()
|
||||
if old_setid in prov:
|
||||
gnss_prov.write_text(prov.replace(old_setid, new_setid, 1))
|
||||
elif "ignoring SUPL set-id request flags" not in prov:
|
||||
short = """ // """ + MARKER + """: AXP/Divest. Never send IMSI or the phone number
|
||||
// to a SUPL server, including during an emergency call. LOS 23 already
|
||||
// skips this outside emergency. Control-plane A-GNSS is unchanged.
|
||||
mGnssNative.setAgpsSetId(AGPS_SETID_TYPE_NONE, "");
|
||||
"""
|
||||
if short not in prov:
|
||||
sys.exit("setAgpsSetId block missing")
|
||||
gnss_prov.write_text(prov.replace(short, new_setid, 1))
|
||||
|
||||
must(
|
||||
loc_xml,
|
||||
""" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
""" settings:controller="com.android.settings.location.LocationServicesPreferenceController"/>
|
||||
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """: default off, so carrier SUPL stays -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="force_disable_supl"
|
||||
android:title="@string/force_disable_supl_title"
|
||||
android:summary="@string/force_disable_supl_summary"
|
||||
settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
already='android:key="force_disable_supl"',
|
||||
)
|
||||
|
||||
must(
|
||||
loc_xml,
|
||||
""" settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
""" settings:controller="com.android.settings.location.ForceDisableSuplPrefController"/>
|
||||
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """: default off. On stops LPP, XTRA and IZat. Binaries stay. -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="force_disable_location_assist"
|
||||
android:title="@string/force_disable_location_assist_title"
|
||||
android:summary="@string/force_disable_location_assist_summary"
|
||||
settings:controller="com.android.settings.location.ForceDisableLocationAssistPrefController"/>
|
||||
|
||||
</com.android.settingslib.widget.UntitledPreferenceCategory>
|
||||
""",
|
||||
already='android:key="force_disable_location_assist"',
|
||||
)
|
||||
|
||||
must(
|
||||
strings,
|
||||
""" <string name="location_services_preference_title">Location services</string>
|
||||
""",
|
||||
""" <string name="location_services_preference_title">Location services</string>
|
||||
<!-- """
|
||||
+ MARKER
|
||||
+ """ -->
|
||||
<string name="force_disable_supl_title">Force disable Secure User Plane Location (SUPL)</string>
|
||||
<string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
""",
|
||||
already="force_disable_supl_title",
|
||||
)
|
||||
|
||||
must(
|
||||
strings,
|
||||
""" <string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
""",
|
||||
""" <string name="force_disable_supl_summary">Always disable SUPL assisted location support regardless of carrier configuration or emergency call status. Does not disable control-plane A-GNSS. IMSI and the phone number are never sent to a SUPL server.</string>
|
||||
<string name="force_disable_location_assist_title">Stop extra location assistance</string>
|
||||
<string name="force_disable_location_assist_summary">Stops LTE positioning (LPP/LPPE), XTRA orbit downloads, and Qualcomm IZat. Satellite fixes keep working. The programs stay installed. SUPL has its own switch.</string>
|
||||
""",
|
||||
already="force_disable_location_assist_title",
|
||||
)
|
||||
|
||||
if not controller.exists():
|
||||
controller.write_text(
|
||||
"""package com.android.settings.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** """
|
||||
+ MARKER
|
||||
+ """ AXP/Graphene toggle. Default off. */
|
||||
public class ForceDisableSuplPrefController extends TogglePreferenceController {
|
||||
|
||||
public ForceDisableSuplPrefController(Context ctx, String key) {
|
||||
super(ctx, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!Process.myUserHandle().isSystem()) {
|
||||
return DISABLED_FOR_USER;
|
||||
}
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Global.getInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_SUPL,
|
||||
Settings.Global.FORCE_DISABLE_SUPL_DEFAULT) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Global.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_SUPL,
|
||||
isChecked ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
assist_controller = (
|
||||
TREE
|
||||
/ "packages/apps/Settings/src/com/android/settings/location/ForceDisableLocationAssistPrefController.java"
|
||||
)
|
||||
if not assist_controller.exists():
|
||||
assist_controller.write_text(
|
||||
"""package com.android.settings.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
/** """
|
||||
+ MARKER
|
||||
+ """ Default off. Stops assistance; does not delete blobs. */
|
||||
public class ForceDisableLocationAssistPrefController extends TogglePreferenceController {
|
||||
|
||||
public ForceDisableLocationAssistPrefController(Context ctx, String key) {
|
||||
super(ctx, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!Process.myUserHandle().isSystem()) {
|
||||
return DISABLED_FOR_USER;
|
||||
}
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.Global.getInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST_DEFAULT) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
return Settings.Global.putInt(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Global.FORCE_DISABLE_LOCATION_ASSIST,
|
||||
isChecked ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceHighlightMenuRes() {
|
||||
return NO_RES;
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
must(
|
||||
init_rc,
|
||||
"""on property:persist.sys.xtra-daemon.enabled=*
|
||||
restart loc_launcher
|
||||
""",
|
||||
"""# """
|
||||
+ MARKER
|
||||
+ """
|
||||
# 1 stops loc_launcher (xtra-daemon, lowi, IZat). Binaries stay.
|
||||
# The xtra property must not restart the service while that stop is on.
|
||||
on property:persist.sys.axp.loc_privacy=1
|
||||
stop loc_launcher
|
||||
exec_background -- /system/bin/toybox killall xtra-daemon lowi-server
|
||||
|
||||
on property:persist.sys.axp.loc_privacy=0
|
||||
start loc_launcher
|
||||
|
||||
on property:sys.boot_completed=1 && property:persist.sys.axp.loc_privacy=1
|
||||
stop loc_launcher
|
||||
exec_background -- /system/bin/toybox killall xtra-daemon lowi-server
|
||||
|
||||
on property:persist.sys.xtra-daemon.enabled=* && property:persist.sys.axp.loc_privacy=0
|
||||
restart loc_launcher
|
||||
""",
|
||||
already="persist.sys.axp.loc_privacy",
|
||||
)
|
||||
|
||||
raw = gps.read_bytes()
|
||||
old_ntp = b"NTP_SERVER = time.google.com"
|
||||
new_ntp = b"NTP_SERVER = 2.android.pool.ntp.org"
|
||||
if new_ntp not in raw:
|
||||
if old_ntp not in raw:
|
||||
sys.exit("NTP_SERVER line missing")
|
||||
raw = raw.replace(old_ntp, new_ntp, 1)
|
||||
gps.write_bytes(raw)
|
||||
print("supl privacy applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""009: AXP Yama ptrace_scope, active at 2.
|
||||
|
||||
AXP LOS 22 init.rc sets /proc/sys/kernel/yama/ptrace_scope from
|
||||
persist.native_debug (true -> 0, false -> 2). GOLDEN's kernel has Yama
|
||||
off, so those lines do nothing there. This tree builds Yama, so init
|
||||
writes 2 at boot. persist.native_debug=true still opens ptrace.
|
||||
|
||||
Writing that sysctl needs CAP_SYS_PTRACE. AOSP neverallows it for init;
|
||||
the exception is the one in AXP's ptrace_scope sepolicy patch. The node
|
||||
is labeled proc_security, which init may already read and write.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
TREE = pathlib.Path("/srv/rom/src/lineage")
|
||||
MARKER = "sunfish-a16-009-yama-ptrace"
|
||||
|
||||
RC_BOOT_OLD = " write /proc/sys/kernel/randomize_va_space 2\n"
|
||||
RC_BOOT_NEW = (
|
||||
" write /proc/sys/kernel/randomize_va_space 2\n"
|
||||
" # sunfish-a16-009-yama-ptrace: AXP scope 2 unless native debug is on.\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 2\n"
|
||||
)
|
||||
RC_PROP_OLD = (
|
||||
" write /proc/sys/net/ipv4/tcp_default_init_rwnd ${net.tcp_def_init_rwnd}\n"
|
||||
)
|
||||
RC_PROP_NEW = (
|
||||
" write /proc/sys/net/ipv4/tcp_default_init_rwnd ${net.tcp_def_init_rwnd}\n"
|
||||
"\n"
|
||||
"on property:persist.native_debug=true\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 0\n"
|
||||
"\n"
|
||||
"on property:persist.native_debug=false\n"
|
||||
" write /proc/sys/kernel/yama/ptrace_scope 2\n"
|
||||
)
|
||||
|
||||
GENFS_OLD = "genfscon proc /sys/kernel/usermodehelper u:object_r:usermodehelper:s0\n"
|
||||
GENFS_NEW = (
|
||||
"genfscon proc /sys/kernel/usermodehelper u:object_r:usermodehelper:s0\n"
|
||||
"genfscon proc /sys/kernel/yama/ptrace_scope u:object_r:proc_security:s0\n"
|
||||
)
|
||||
|
||||
PROP_OLD = "persist.debug. u:object_r:persist_debug_prop:s0\n"
|
||||
PROP_NEW = (
|
||||
"persist.debug. u:object_r:persist_debug_prop:s0\n"
|
||||
"persist.native_debug u:object_r:system_prop:s0\n"
|
||||
)
|
||||
|
||||
INIT_OLD = """allow init {
|
||||
proc_security
|
||||
}:file rw_file_perms;
|
||||
"""
|
||||
INIT_NEW = """allow init {
|
||||
proc_security
|
||||
}:file rw_file_perms;
|
||||
|
||||
# sunfish-a16-009-yama-ptrace: CAP_SYS_PTRACE to set ptrace_scope.
|
||||
allow init self:global_capability_class_set sys_ptrace;
|
||||
"""
|
||||
|
||||
NEVER_END = "} self:global_capability_class_set sys_ptrace;"
|
||||
|
||||
|
||||
def must(path: pathlib.Path, old: str, new: str, already: str) -> None:
|
||||
text = path.read_text()
|
||||
if already in text:
|
||||
return
|
||||
if old not in text:
|
||||
sys.exit(f"anchor missing in {path}")
|
||||
path.write_text(text.replace(old, new, 1))
|
||||
|
||||
|
||||
def loosen_sys_ptrace(path: pathlib.Path) -> None:
|
||||
text = path.read_text()
|
||||
idx = text.find(NEVER_END)
|
||||
if idx < 0:
|
||||
return
|
||||
start = text.rfind("neverallow {", 0, idx)
|
||||
if start < 0:
|
||||
sys.exit(f"neverallow block missing in {path}")
|
||||
block = text[start:idx]
|
||||
if "\n -init\n" in block:
|
||||
return
|
||||
if "\n domain\n" not in block:
|
||||
sys.exit(f"domain line missing in sys_ptrace neverallow {path}")
|
||||
new_block = block.replace("\n domain\n", "\n domain\n -init\n", 1)
|
||||
path.write_text(text[:start] + new_block + text[idx:])
|
||||
|
||||
|
||||
def main() -> None:
|
||||
rc = TREE / "system/core/rootdir/init.rc"
|
||||
must(rc, RC_BOOT_OLD, RC_BOOT_NEW, MARKER)
|
||||
must(rc, RC_PROP_OLD, RC_PROP_NEW, "on property:persist.native_debug=true")
|
||||
|
||||
se = TREE / "system/sepolicy"
|
||||
must(
|
||||
se / "private/init.te",
|
||||
INIT_OLD,
|
||||
INIT_NEW,
|
||||
"allow init self:global_capability_class_set sys_ptrace;",
|
||||
)
|
||||
loosen_sys_ptrace(se / "private/domain.te")
|
||||
must(se / "private/genfs_contexts", GENFS_OLD, GENFS_NEW, "yama/ptrace_scope")
|
||||
must(se / "private/property_contexts", PROP_OLD, PROP_NEW, "persist.native_debug")
|
||||
|
||||
api = se / "prebuilts/api"
|
||||
for domain in api.glob("*/private/domain.te"):
|
||||
loosen_sys_ptrace(domain)
|
||||
for genfs in api.glob("*/private/genfs_contexts"):
|
||||
text = genfs.read_text()
|
||||
if "yama/ptrace_scope" in text or GENFS_OLD not in text:
|
||||
continue
|
||||
genfs.write_text(text.replace(GENFS_OLD, GENFS_NEW, 1))
|
||||
for props in api.glob("*/private/property_contexts"):
|
||||
text = props.read_text()
|
||||
if "persist.native_debug" in text or PROP_OLD not in text:
|
||||
continue
|
||||
props.write_text(text.replace(PROP_OLD, PROP_NEW, 1))
|
||||
|
||||
# Current policy must still exclude init, or the write is neverallowed.
|
||||
live = (se / "private/domain.te").read_text()
|
||||
end = live.find(NEVER_END)
|
||||
start = live.rfind("neverallow {", 0, end)
|
||||
if "\n -init\n" not in live[start:end]:
|
||||
sys.exit("init still neverallowed from sys_ptrace")
|
||||
print("yama ptrace_scope applied")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -69,12 +69,12 @@ guarantee). Do not relock the bootloader on this Magisk track.
|
||||
|
||||
## Branding
|
||||
|
||||
`TARGET_UNOFFICIAL_BUILD_ID=AXP-Resurection-Pro` is set at the **top** of
|
||||
`device/google/sunfish/lineage_sunfish.mk` (before inheriting
|
||||
`vendor/lineage` → `version.mk`). Helper:
|
||||
`apply_009_unofficial_build_id.py`. **Pro** = full Magisk resurrection track
|
||||
(not a future slim/minimal variant). Mirrors GOLDEN’s `…-sunfish-pro` /
|
||||
releasetype `PRO` intent without patching `vendor/lineage/config/version.mk`.
|
||||
Ship identity follows AXP/GOLDEN, not Lineage's unofficial channel.
|
||||
GOLDEN (`22.2-2026.003-sunfish-pro`) reports `ro.lineage.releasetype=PRO`,
|
||||
`ro.build.tags=release-keys`, and a version ending in `sunfish-pro`.
|
||||
`TARGET_UNOFFICIAL_BUILD_ID` forces Lineage `UNOFFICIAL` and is not that
|
||||
scheme. The next bacon sets `PRO` + `release-keys` + `…-sunfish-pro`.
|
||||
**Pro** remains the full Magisk track (AXP PRO, not SLIM).
|
||||
|
||||
`branding.mk` adds `ro.axp.resurection.track=pro`. Ship scripts also publish
|
||||
`AXP-Resurection-Pro-<ver>-<date>-sunfish.zip` as a hardlink/copy of the
|
||||
|
||||
Reference in new issue
Block a user