Merge RP1A.191024.001
Change-Id: I5cda3bba276e99d948b752be87d4599e9f882e0f
diff --git a/Android.bp b/Android.bp
old mode 100644
new mode 100755
diff --git a/Android.mk b/Android.mk
old mode 100644
new mode 100755
diff --git a/api/current.txt b/api/current.txt
index 6d2221e..6c8d82e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -48658,6 +48658,7 @@
method public static boolean logEvent(int);
method public static boolean logStart(int);
method public static boolean logStop(int);
+ method public static void write(int, @NonNull java.lang.Object...);
}
public class StringBuilderPrinter implements android.util.Printer {
diff --git a/api/system-current.txt b/api/system-current.txt
index 35b096d..e790b3f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9678,6 +9678,7 @@
public class ImsUtImplBase {
ctor public ImsUtImplBase();
method public void close();
+ method public int queryCFForServiceClass(int, String, int);
method public int queryCallBarring(int);
method public int queryCallBarringForServiceClass(int, int);
method public int queryCallForward(int, String);
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 8be95e4..6f99684 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -18,6 +18,7 @@
shared_libs: [
"libandroid_runtime",
+ "libbase",
"libbinder",
"libcutils",
"libdl",
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 12083b6..002df80 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -21,8 +21,11 @@
#include <cutils/properties.h>
#include <cutils/trace.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android-base/properties.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
+using android::base::GetProperty;
+
namespace android {
static void app_usage()
@@ -172,6 +175,13 @@
int main(int argc, char* const argv[])
{
+ std::string bootmode = GetProperty("ro.bootmode", "");
+
+ if ((strncmp(bootmode.c_str(), "ffbm-00", 7) == 0)
+ || (strncmp(bootmode.c_str(), "ffbm-01", 7) == 0)) {
+ return 0;
+ }
+
if (!LOG_NDEBUG) {
String8 argv_String;
for (int i = 0; i < argc; ++i) {
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
old mode 100644
new mode 100755
index 847dda3..b1d2c9e
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -226,9 +226,6 @@
int idmap_scan(const char *target_package_name, const char *target_apk_path,
const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
{
- String8 filename = String8(idmap_dir);
- filename.appendPath("overlays.list");
-
SortedVector<Overlay> overlayVector;
const size_t N = overlay_dirs->size();
for (size_t i = 0; i < N; ++i) {
@@ -243,39 +240,58 @@
struct stat st;
char overlay_apk_path[PATH_MAX + 1];
snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
+
if (stat(overlay_apk_path, &st) < 0) {
continue;
}
- if (!S_ISREG(st.st_mode)) {
+
+ if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
continue;
}
- int priority = parse_apk(overlay_apk_path, target_package_name);
- if (priority < 0) {
- continue;
+ if (S_ISDIR(st.st_mode)) {
+ String8 dir_name = String8(overlay_apk_path).getPathLeaf();
+ if (dir_name == "." || dir_name == "..") {
+ // Skip the "." and ".." dir.
+ continue;
+ }
+ android::Vector<const char *> ovector;
+ ovector.push(overlay_apk_path);
+ idmap_scan(target_package_name, target_apk_path, idmap_dir, &ovector);
+ } else {
+ int priority = parse_apk(overlay_apk_path, target_package_name);
+ if (priority < 0) {
+ continue;
+ }
+
+ String8 filename = String8(idmap_dir);
+ filename.appendPath("overlays.list");
+ if (unlink(filename.string()) != 0 && errno != ENOENT) {
+ return EXIT_FAILURE;
+ }
+
+ String8 idmap_path(idmap_dir);
+ idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
+ idmap_path.append("@idmap");
+ if (idmap_create_path(target_apk_path, overlay_apk_path,
+ idmap_path.string()) != 0) {
+ ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
+ target_apk_path, overlay_apk_path, idmap_path.string());
+ continue;
+ }
+
+ Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
+ overlayVector.add(overlay);
+
+ if (!writePackagesList(filename.string(), overlayVector)) {
+ return EXIT_FAILURE;
+ }
}
-
- String8 idmap_path(idmap_dir);
- idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
- idmap_path.append("@idmap");
-
- if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
- ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
- target_apk_path, overlay_apk_path, idmap_path.string());
- continue;
- }
-
- Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
- overlayVector.add(overlay);
}
closedir(dir);
}
- if (!writePackagesList(filename.string(), overlayVector)) {
- return EXIT_FAILURE;
- }
-
return EXIT_SUCCESS;
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index f4e465a..b08269d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -478,6 +478,7 @@
* @return The account's password, null if none or if the account doesn't exist
*/
public String getPassword(final Account account) {
+ android.util.SeempLog.record(22);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.getPassword(account);
@@ -508,6 +509,7 @@
* @return The user data, null if the account, key doesn't exist, or the user is locked
*/
public String getUserData(final Account account, final String key) {
+ android.util.SeempLog.record(23);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -761,6 +763,7 @@
return new Future2Task<String>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
}
@@ -805,6 +808,7 @@
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
}
@Override
@@ -865,6 +869,7 @@
return new Future2Task<Account[]>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAccountsByFeatures(mResponse, type, features,
mContext.getOpPackageName());
}
@@ -909,6 +914,7 @@
* already exists, the account is null, the user is locked, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
+ android.util.SeempLog.record(24);
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.addAccountExplicitly(account, password, userdata);
@@ -1126,6 +1132,7 @@
return new Future2Task<Account>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.renameAccount(mResponse, account, newName);
}
@Override
@@ -1186,10 +1193,12 @@
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
+ android.util.SeempLog.record(25);
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccount(mResponse, account, false);
}
@Override
@@ -1245,10 +1254,12 @@
*/
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccount(mResponse, account, activity != null);
}
}.start();
@@ -1270,6 +1281,7 @@
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
@Override
@@ -1296,6 +1308,7 @@
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.removeAccountAsUser(mResponse, account, activity != null,
userHandle.getIdentifier());
}
@@ -1409,6 +1422,7 @@
* @param password The password to set, null to clear the password
*/
public void setPassword(final Account account, final String password) {
+ android.util.SeempLog.record(26);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.setPassword(account, password);
@@ -1437,6 +1451,7 @@
* @param account The account whose password to clear
*/
public void clearPassword(final Account account) {
+ android.util.SeempLog.record(27);
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.clearPassword(account);
@@ -1464,6 +1479,7 @@
* @param value String value to set, {@code null} to clear this user data key
*/
public void setUserData(final Account account, final String key, final String value) {
+ android.util.SeempLog.record(28);
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
@@ -1614,6 +1630,7 @@
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
optionsIn);
@@ -1785,6 +1802,7 @@
return new AmsTask(null, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.getAuthToken(mResponse, account, authTokenType,
notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
}
@@ -1845,6 +1863,7 @@
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+ android.util.SeempLog.record(29);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
final Bundle optionsIn = new Bundle();
if (addAccountOptions != null) {
@@ -1855,6 +1874,7 @@
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccount(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn);
}
@@ -1880,6 +1900,7 @@
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.addAccountAsUser(mResponse, accountType, authTokenType,
requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
}
@@ -1929,6 +1950,7 @@
return new Future2Task<Boolean>(handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(34);
mService.copyAccountToUser(
mResponse, account, fromUser.getIdentifier(), toUser.getIdentifier());
}
@@ -2056,6 +2078,7 @@
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
userId);
}
@@ -2169,10 +2192,12 @@
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
+ android.util.SeempLog.record(30);
if (accountType == null) throw new IllegalArgumentException("accountType is null");
return new AmsTask(activity, handler, callback) {
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
mService.editProperties(mResponse, accountType, activity != null);
}
}.start();
@@ -2599,6 +2624,7 @@
@Override
public void doWork() throws RemoteException {
+ android.util.SeempLog.record(31);
getAccountByTypeAndFeatures(mAccountType, mFeatures,
new AccountManagerCallback<Bundle>() {
@Override
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 92aabb5..ee928ee 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -353,4 +353,7 @@
* Unregisters the specified {@code processObserver}.
*/
public abstract void unregisterProcessObserver(IProcessObserver processObserver);
+
+ // Starts a process as empty.
+ public abstract int startActivityAsUserEmpty(Bundle options);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7f27368..d6458ec 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -130,6 +130,7 @@
import android.system.StructStat;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
+import android.util.BoostFramework;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -6214,6 +6215,8 @@
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
+ long st_bindApp = SystemClock.uptimeMillis();
+ BoostFramework ux_perf = null;
// Register the UI Thread as a sensitive thread to the runtime.
VMRuntime.registerSensitiveThread();
// In the case the stack depth property exists, pass it down to the runtime.
@@ -6315,10 +6318,17 @@
/**
* Switch this process to density compatibility mode if needed.
*/
- if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
+ if ((data.appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
+ } else {
+ int overrideDensity = data.appInfo.getOverrideDensity();
+ if(overrideDensity != 0) {
+ Log.d(TAG, "override app density from " + DisplayMetrics.DENSITY_DEVICE + " to " + overrideDensity);
+ mDensityCompatMode = true;
+ Bitmap.setDefaultDensity(overrideDensity);
+ }
}
updateDefaultDensity();
@@ -6440,6 +6450,15 @@
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated()) {
+ final int old_mask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ ux_perf = new BoostFramework(appContext);
+ } finally {
+ StrictMode.setThreadPolicyMask(old_mask);
+ }
+ }
+
+ if (!Process.isIsolated()) {
final int oldMask = StrictMode.allowThreadDiskWritesMask();
try {
setupGraphicsSupport(appContext);
@@ -6589,6 +6608,28 @@
throw e.rethrowFromSystemServer();
}
}
+ long end_bindApp = SystemClock.uptimeMillis();
+ int bindApp_dur = (int) (end_bindApp - st_bindApp);
+ String pkg_name = null;
+ if (appContext != null) {
+ pkg_name = appContext.getPackageName();
+ }
+ if (ux_perf != null && !Process.isIsolated() && pkg_name != null) {
+ String pkgDir = null;
+ try
+ {
+ String codePath = appContext.getPackageCodePath();
+ pkgDir = codePath.substring(0, codePath.lastIndexOf('/'));
+ }
+ catch(Exception e)
+ {
+ Slog.e(TAG, "HeavyGameThread () : Exception_1 = " + e);
+ }
+ ux_perf.perfUXEngine_events(BoostFramework.UXE_EVENT_BINDAPP, 0,
+ pkg_name,
+ bindApp_dur,
+ pkgDir);
+ }
}
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 588acee..a8cf5e1 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -491,6 +491,7 @@
*/
@NonNull
public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) {
+ android.util.SeempLog.record_str(376, intent.toString());
validateNotAppThread();
synchronized (mSync) {
@@ -1677,6 +1678,7 @@
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
@@ -1750,6 +1752,7 @@
public int execStartActivitiesAsUser(Context who, IBinder contextThread,
IBinder token, Activity target, Intent[] intents, Bundle options,
int userId) {
+ android.util.SeempLog.record_str(378, intents.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1821,6 +1824,7 @@
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String target,
Intent intent, int requestCode, Bundle options) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1888,6 +1892,7 @@
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, String resultWho,
Intent intent, int requestCode, Bundle options, UserHandle user) {
+ android.util.SeempLog.record_str(377, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1982,6 +1987,7 @@
public void execStartActivityFromAppTask(
Context who, IBinder contextThread, IAppTask appTask,
Intent intent, Bundle options) {
+ android.util.SeempLog.record_str(380, intent.toString());
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 68ab89c..dc01a92 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -180,7 +180,7 @@
}
}
- private static final boolean ENABLE_APK_ASSETS_CACHE = false;
+ private static final boolean ENABLE_APK_ASSETS_CACHE = true;
/**
* The ApkAssets we are caching and intend to hold strong references to.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e7ba85a..e690786 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -736,6 +736,7 @@
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(String address) {
+ android.util.SeempLog.record(62);
return new BluetoothDevice(address);
}
@@ -751,6 +752,7 @@
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(byte[] address) {
+ android.util.SeempLog.record(62);
if (address == null || address.length != 6) {
throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
}
@@ -985,6 +987,7 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
@AdapterState
public int getState() {
+ android.util.SeempLog.record(63);
int state = BluetoothAdapter.STATE_OFF;
try {
@@ -1089,6 +1092,7 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
+ android.util.SeempLog.record(56);
if (isEnabled()) {
if (DBG) {
Log.d(TAG, "enable(): BT already enabled!");
@@ -1126,6 +1130,7 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean disable() {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(ActivityThread.currentPackageName(), true);
} catch (RemoteException e) {
@@ -1145,6 +1150,7 @@
*/
@UnsupportedAppUsage
public boolean disable(boolean persist) {
+ android.util.SeempLog.record(57);
try {
return mManagerService.disable(ActivityThread.currentPackageName(), persist);
@@ -1199,10 +1205,10 @@
public boolean factoryReset() {
try {
mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.factoryReset();
+ if (mManagerService != null) {
+ SystemProperties.set("persist.bluetooth.factoryreset", "true");
+ return mManagerService.factoryReset();
}
- SystemProperties.set("persist.bluetooth.factoryreset", "true");
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
@@ -1624,6 +1630,7 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean startDiscovery() {
+ android.util.SeempLog.record(58);
if (getState() != STATE_ON) {
return false;
}
@@ -2033,6 +2040,7 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public Set<BluetoothDevice> getBondedDevices() {
+ android.util.SeempLog.record(61);
if (getState() != STATE_ON) {
return toDeviceSet(new BluetoothDevice[0]);
}
@@ -2130,6 +2138,7 @@
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getProfileConnectionState(int profile) {
+ android.util.SeempLog.record(64);
if (getState() != STATE_ON) {
return BluetoothProfile.STATE_DISCONNECTED;
}
@@ -2261,6 +2270,7 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
+ android.util.SeempLog.record(59);
return createNewRfcommSocketAndRecord(name, uuid, false, false);
}
@@ -2531,6 +2541,9 @@
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
+ } else if (profile == BluetoothProfile.DUN) {
+ BluetoothDun dun = new BluetoothDun(context, listener);
+ return true;
} else if (profile == BluetoothProfile.HEALTH) {
Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
return false;
@@ -2603,6 +2616,10 @@
BluetoothPan pan = (BluetoothPan) proxy;
pan.close();
break;
+ case BluetoothProfile.DUN:
+ BluetoothDun dun = (BluetoothDun)proxy;
+ dun.close();
+ break;
case BluetoothProfile.GATT:
BluetoothGatt gatt = (BluetoothGatt) proxy;
gatt.close();
@@ -2638,6 +2655,7 @@
case BluetoothProfile.HEARING_AID:
BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
hearingAid.close();
+ break;
}
}
@@ -2699,6 +2717,8 @@
}
synchronized (mProxyServiceStateCallbacks) {
+ Log.d(TAG, "onBluetoothServiceDown: Sending callbacks to " +
+ mProxyServiceStateCallbacks.size() + " clients");
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
try {
if (cb != null) {
@@ -2711,6 +2731,7 @@
}
}
}
+ Log.d(TAG, "onBluetoothServiceDown: Finished sending callbacks to registered clients");
}
public void onBrEdrDown() {
@@ -2803,6 +2824,22 @@
}
}
+ /**
+ * @hide
+ */
+ public void unregisterAdapter() {
+ try {
+ //mServiceLock.writeLock().lock();
+ if (mManagerService != null){
+ mManagerService.unregisterAdapter(mManagerCallback);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ //mServiceLock.writeLock().unlock();
+ }
+ }
+
private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
return Collections.unmodifiableSet(deviceSet);
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 36f3a1e..c449c32 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -42,9 +42,18 @@
@UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
@UnsupportedAppUsage
- public static final int SOURCE_CODEC_TYPE_LDAC = 4;
+ public static final int SOURCE_CODEC_TYPE_APTX_ADAPTIVE = 4;
@UnsupportedAppUsage
- public static final int SOURCE_CODEC_TYPE_MAX = 5;
+ public static final int SOURCE_CODEC_TYPE_LDAC = 5;
+ @UnsupportedAppUsage
+ public static final int SOURCE_CODEC_TYPE_APTX_TWSP = 6;
+ @UnsupportedAppUsage
+ public static final int SOURCE_CODEC_TYPE_MAX = 7;
+ /* CELT is not an A2DP Codec and only used to fetch encoder
+ ** format for BA usecase, moving out of a2dp codec value list
+ */
+ @UnsupportedAppUsage
+ public static final int SOURCE_CODEC_TYPE_CELT = 8;
@UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
@@ -301,6 +310,10 @@
return "aptX HD";
case SOURCE_CODEC_TYPE_LDAC:
return "LDAC";
+ case SOURCE_CODEC_TYPE_APTX_ADAPTIVE:
+ return "aptX Adaptive";
+ case SOURCE_CODEC_TYPE_APTX_TWSP:
+ return "aptX TWS+";
case SOURCE_CODEC_TYPE_INVALID:
return "INVALID CODEC";
default:
@@ -537,6 +550,10 @@
if (mCodecSpecific1 != other.mCodecSpecific1) {
return false;
}
+ case SOURCE_CODEC_TYPE_APTX_ADAPTIVE:
+ if (other.mCodecSpecific4 > 0) {
+ return false;
+ }
// fall through
default:
return true;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c616044..3c7b7c4 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1,4 +1,39 @@
/*
+ * Copyright (C) 2017, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -194,6 +229,18 @@
public static final String ACTION_BOND_STATE_CHANGED =
"android.bluetooth.device.action.BOND_STATE_CHANGED";
+ /**
+ * Broadcast Action: Broadcast details of IOT device when an IOT
+ * related issue is observed.
+ * <p>Always contains the extra fields {@link #EXTRA_NAME}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
+ **/
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_REMOTE_ISSUE_OCCURRED =
+ "org.codeaurora.intent.bluetooth.action.REMOTE_ISSUE_OCCURRED";
+
/**
* Broadcast Action: Indicates the battery level of a remote device has
* been retrieved for the first time, or changed since the last retrieval
@@ -226,6 +273,17 @@
public static final int BATTERY_LEVEL_UNKNOWN = -1;
/**
+ * Broadcast Action: Indicates the remote devices are TWS plus earbuds pair.
+ * <p>Always contains the extra fields {@link #EXTRA_TWS_PLUS_DEVICE1},
+ * {@link #EXTRA_TWS_PLUS_DEVICE2}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_TWS_PLUS_DEVICE_PAIR =
+ "android.bluetooth.device.action.TWS_PLUS_DEVICE_PAIR";
+
+ /**
* Used as a Parcelable {@link BluetoothDevice} extra field in every intent
* broadcast by this class. It contains the {@link BluetoothDevice} that
* the intent applies to.
@@ -239,6 +297,77 @@
public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
/**
+ * Used as a Parcelable {@link BluetoothQualityReport} extra field in
+ * {@link #ACTION_REMOTE_ISSUE_OCCURRED} intent. It contains the {@link BluetoothQualityReport}.
+ * @hide
+ */
+ public static final String EXTRA_BQR = "android.bluetooth.qti.extra.EXTRA_BQR";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED}
+ * intents. It contains the type of IOT issue that occurred.
+ * @hide
+ */
+ public static final String EXTRA_ISSUE_TYPE = "android.bluetooth.qti.extra.ERROR_TYPE";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the details of details of the issue.
+ * @hide
+ */
+ public static final String EXTRA_ERROR_CODE = "android.bluetooth.qti.extra.ERROR_CODE";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the SoC event mask when issue occurred.
+ * @hide
+ */
+ public static final String EXTRA_ERROR_EVENT_MASK = "android.bluetooth.qti.extra.ERROR_EVENT_MASK";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the LMP Version of IOT device.
+ * @hide
+ */
+ public static final String EXTRA_LMP_VERSION = "android.bluetooth.qti.extra.EXTRA_LMP_VERSION";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the LMP Sub Version of IOT device.
+ * @hide
+ */
+ public static final String EXTRA_LMP_SUBVER = "android.bluetooth.qti.extra.EXTRA_LMP_SUBVER";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the Manufacturer ID of IOT device.
+ * @hide
+ */
+ public static final String EXTRA_MANUFACTURER = "android.bluetooth.qti.extra.EXTRA_MANUFACTURER";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the Power level.
+ * @hide
+ */
+ public static final String EXTRA_POWER_LEVEL = "android.bluetooth.qti.extra.EXTRA_POWER_LEVEL";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the Link Quality of the connection.
+ * @hide
+ */
+ public static final String EXTRA_LINK_QUALITY = "android.bluetooth.qti.extra.EXTRA_LINK_QUALITY";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_REMOTE_ISSUE_OCCURRED} intents.
+ * It contains the coutnt of glitches occured since last broadcast.
+ * @hide
+ */
+ public static final String EXTRA_GLITCH_COUNT = "android.bluetooth.qti.extra.EXTRA_GLITCH_COUNT";
+
+
+ /**
* Used as an optional short extra field in {@link #ACTION_FOUND} intents.
* Contains the RSSI value of the remote device as reported by the
* Bluetooth hardware.
@@ -270,6 +399,23 @@
*/
public static final String EXTRA_PREVIOUS_BOND_STATE =
"android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_TWS+_DEVICE_PAIR}
+ * intents. It contains the first TWS+ earbud address of pair.
+ * @hide
+ */
+ public static final String EXTRA_TWS_PLUS_DEVICE1 =
+ "android.bluetooth.device.extra.EXTRA_TWS_PLUS_DEVICE1";
+
+ /**
+ * Used as a String extra field in {@link #ACTION_TWS+_DEVICE_PAIR}
+ * intents. It contains the second TWS+ earbud address of pair.
+ * @hide
+ */
+ public static final String EXTRA_TWS_PLUS_DEVICE2 =
+ "android.bluetooth.device.extra.EXTRA_TWS_PLUS_DEVICE2";
+
/**
* Indicates the remote device is not bonded (paired).
* <p>There is no shared link key with the remote device, so communication
@@ -884,10 +1030,12 @@
/*package*/
@UnsupportedAppUsage
static IBluetooth getService() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetooth tService = adapter.getBluetoothService(sStateChangeCallback);
+
synchronized (BluetoothDevice.class) {
if (sService == null) {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- sService = adapter.getBluetoothService(sStateChangeCallback);
+ sService = tService;
}
}
return sService;
@@ -898,9 +1046,10 @@
public void onBluetoothServiceUp(IBluetooth bluetoothService)
throws RemoteException {
synchronized (BluetoothDevice.class) {
- if (sService == null) {
- sService = bluetoothService;
+ if (sService != null) {
+ Log.w(TAG, "sService is not NULL");
}
+ sService = bluetoothService;
}
}
@@ -1247,6 +1396,22 @@
return false;
}
+ /** @hide */
+ @UnsupportedAppUsage
+ public void setBondingInitiatedLocally(boolean localInitiated) {
+ final IBluetooth service = sService;
+ if (service == null) {
+ Log.w(TAG, "BT not enabled, setBondingInitiatedLocally failed");
+ return;
+ }
+ try {
+ service.setBondingInitiatedLocally(this, localInitiated);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return;
+ }
+
/**
* Set the Out Of Band data for a remote device to be used later
* in the pairing mechanism. Users can obtain this data through other
@@ -1505,6 +1670,41 @@
}
/**
+ * Returns whether if the device is TWS+ device.
+ *
+ * @return True if the devcie is TWS+ device.
+ * @hide
+ */
+ public boolean isTwsPlusDevice() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
+ return false;
+ }
+ try {
+ return sService.isTwsPlusDevice(this);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Get the TWS+ peer address of the remote device.
+ *
+ * @return the TWS+ peer address of the remote device if available, otherwise
+ * null.
+ * @hide
+ */
+ public String getTwsPlusPeerAddress() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
+ return null;
+ }
+ try {
+ return sService.getTwsPlusPeerAddress(this);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
+ /**
* Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
diff --git a/core/java/android/bluetooth/BluetoothDun.java b/core/java/android/bluetooth/BluetoothDun.java
new file mode 100644
index 0000000..cbf44e5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDun.java
@@ -0,0 +1,296 @@
+/*
+*Copyright (c) 2018, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the APIs to control the Bluetooth Dun
+ * Profile.
+ *
+ *<p>BluetoothDun is a proxy object for controlling the Bluetooth DUN
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothDun proxy object.
+ *
+ *<p>Each method is protected with its appropriate permission.
+ *@hide
+ */
+public final class BluetoothDun implements BluetoothProfile {
+ private static final String TAG = "BluetoothDun";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Dun
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "codeaurora.bluetooth.dun.profile.action.CONNECTION_STATE_CHANGED";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private BluetoothAdapter mAdapter;
+ private IBluetoothDun mDunService;
+
+ /**
+ * Create a BluetoothDun proxy object for interacting with the local
+ * Bluetooth Service which handles the Dun profile
+ *
+ */
+ /*package*/ BluetoothDun(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ try {
+ mAdapter.getBluetoothManager().registerStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to register BluetoothStateChangeCallback",re);
+ }
+ Log.d(TAG, "BluetoothDun() call bindService");
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothDun.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Dun Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+
+ /*package*/ void close() {
+ if (VDBG) log("close()");
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.w(TAG,"Unable to unregister BluetoothStateChangeCallback",re);
+ }
+ }
+
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ protected void finalize() {
+ close();
+ }
+
+ private IBluetoothStateChangeCallback mStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ //Handle enable request to bind again.
+ Log.d(TAG, "onBluetoothStateChange on: " + on);
+ if (on) {
+ try {
+ if (mDunService == null) {
+ Log.d(TAG, "onBluetoothStateChange call bindService");
+ doBind();
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG,"onBluetoothStateChange: could not bind to DUN service: ", e);
+ }
+ } else {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ if ( mDunService != null) {
+ try {
+ mDunService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Initiate disconnection from DUN server.
+ *
+ * <p> Once the disconnection is initiated by any device either local host
+ * or remote device, the state will transition from {@link #STATE_CONNECTED}
+ * to {@link #STATE_DISCONNECTED}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mDunService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mDunService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mDunService != null && isEnabled()) {
+ try {
+ return mDunService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mDunService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mDunService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mDunService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object connected");
+ mDunService = IBluetoothDun.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.DUN,
+ BluetoothDun.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "BluetoothDUN Proxy object disconnected");
+ mDunService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.DUN);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 672174f..147e5ef 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -33,8 +33,11 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Public API for controlling the Bluetooth Headset Service. This includes both
@@ -283,6 +286,41 @@
public static final int STATE_AUDIO_CONNECTED = 12;
/**
+ * Intent used to broadcast the Battery status of TWS+ devices
+ *
+ * <p>This intent will have 2 extras:
+ * <ul>
+ * <li> {@link #EXTRA_HF_TWSP_BATTERY_STATE} - Current Battey state of TWS+
+ * device. 0 for Discharging, 1 for Charging
+ * <\li>
+ * <li> {@link #EXTRA_HF_TWSP_BATTERY_LEVEL} - Current Battey charging level
+ * in percentage of TWS+ device.
+ * <\li>
+ *
+ * @hide
+ */
+ public static final String ACTION_HF_TWSP_BATTERY_STATE_CHANGED =
+ "android.bluetooth.headset.action.HF_TWSP_BATTERY_STATE_CHANGED";
+
+ /**
+ * A int extra field in {@link #EXTRA_HF_TWSP_BATTERY_STATE}
+ * intents that contains the battery state of TWS+ device
+ *
+ * @hide
+ */
+ public static final String EXTRA_HF_TWSP_BATTERY_STATE =
+ "android.bluetooth.headset.extra.HF_TWSP_BATTERY_STATE";
+
+ /**
+ * A int extra field in {@link #EXTRA_HF_TWSP_BATTERY_LEVEL}
+ * intents that contains the value of battery level in percentage for TWS+ device
+ * @hide
+ */
+ public static final String EXTRA_HF_TWSP_BATTERY_LEVEL =
+ "android.bluetooth.headset.extra.HF_TWSP_BATTERY_LEVEL";
+
+
+ /**
* Intent used to broadcast the headset's indicator status
*
* <p>This intent will have 3 extras:
@@ -328,7 +366,8 @@
private Context mContext;
private ServiceListener mServiceListener;
- private volatile IBluetoothHeadset mService;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock") private IBluetoothHeadset mService;
private BluetoothAdapter mAdapter;
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
@@ -366,7 +405,7 @@
private boolean doBind() {
synchronized (mConnection) {
if (mService == null) {
- if (VDBG) Log.d(TAG, "Binding service...");
+ if (DBG) Log.d(TAG, "Binding service...");
try {
return mAdapter.getBluetoothManager().bindBluetoothProfileService(
BluetoothProfile.HEADSET, mConnection);
@@ -380,15 +419,17 @@
private void doUnbind() {
synchronized (mConnection) {
+ if (DBG) Log.d(TAG, "Unbinding service...");
if (mService != null) {
- if (VDBG) Log.d(TAG, "Unbinding service...");
try {
mAdapter.getBluetoothManager().unbindBluetoothProfileService(
BluetoothProfile.HEADSET, mConnection);
} catch (RemoteException e) {
Log.e(TAG, "Unable to unbind HeadsetService", e);
} finally {
+ mServiceLock.writeLock().lock();
mService = null;
+ mServiceLock.writeLock().unlock();
}
}
}
@@ -416,6 +457,10 @@
doUnbind();
}
+ protected void finalize() throws Throwable {
+ close();
+ }
+
/**
* Initiate connection to a profile of the remote bluetooth device.
*
@@ -502,17 +547,22 @@
@Override
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.getConnectedDevices();
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- return new ArrayList<BluetoothDevice>();
+ try {
+ mServiceLock.readLock().lock();
+ final IBluetoothHeadset service = mService;
+ if (service != null && isEnabled()) {
+ try {
+ return service.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
}
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return new ArrayList<BluetoothDevice>();
}
/**
@@ -692,14 +742,19 @@
public boolean isAudioConnected(BluetoothDevice device) {
if (VDBG) log("isAudioConnected()");
final IBluetoothHeadset service = mService;
- if (service != null && isEnabled() && isValidDevice(device)) {
- try {
- return service.isAudioConnected(device);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ try {
+ mServiceLock.readLock().lock();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.isAudioConnected(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
}
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (service == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
@@ -1158,17 +1213,26 @@
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service));
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_CONNECTED));
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service));
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MESSAGE_HEADSET_SERVICE_CONNECTED));
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
- doUnbind();
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_DISCONNECTED));
+ try {
+ mServiceLock.writeLock().lock();
+ mHandler.sendMessage(mHandler.obtainMessage(
+ MESSAGE_HEADSET_SERVICE_DISCONNECTED));
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
}
};
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index a812c32..39eb132 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -125,6 +125,7 @@
public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
private BluetoothAdapter mAdapter;
+
private final BluetoothProfileConnector<IBluetoothHearingAid> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.HEARING_AID,
"BluetoothHearingAid", IBluetoothHearingAid.class.getName()) {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index dabe0fd..9d9890c 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -202,12 +202,18 @@
int HEARING_AID = 21;
/**
+ * DUN
+ * @hide
+ */
+ public static final int DUN = 22;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 21;
+ int MAX_PROFILE_ID = 22;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothQualityReport.java b/core/java/android/bluetooth/BluetoothQualityReport.java
new file mode 100644
index 0000000..bc52b9b
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothQualityReport.java
@@ -0,0 +1,1389 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * This class provides the public APIs to access the data of BQR event reported
+ * from firmware side. Currently it supports five event types: Quality monitor event,
+ * Approaching LSTO event, A2DP choppy event, SCO choppy event and Connect fail event.
+ * To know which kind of event is wrapped in this {@link BluetoothQualityReport} object,
+ * you need to call {@link #getQualityReportId}.
+ * <ul>
+ * <li> For Quality monitor event, you can call {@link #getBqrCommon} to get a
+ * {@link BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrVsCommon} to get a
+ * {@link BluetoothQualityReport.BqrVsCommon} object.
+ * <li> For Approaching LSTO event, you can call {@link #getBqrCommon} to get a
+ * {@link BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrVsCommon} to get a
+ * {@link BluetoothQualityReport.BqrVsCommon} object, and call {@link #getBqrVsLsto} to get a
+ * {@link BluetoothQualityReport.BqrVsLsto} object.
+ * <li> For A2DP choppy event, you can call {@link #getBqrCommon} to get a
+ * {@link BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrVsCommon} to get a
+ * {@link BluetoothQualityReport.BqrVsCommon} object, and call {@link #getBqrVsA2dpChoppy} to
+ * get a {@link BluetoothQualityReport.BqrVsA2dpChoppy} object.
+ * <li> For SCO choppy event, you can call {@link #getBqrCommon} to get a
+ * {@link BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrVsCommon} to get a
+ * {@link BluetoothQualityReport.BqrVsCommon} object, and call {@link #getBqrVsScoChoppy} to
+ * get a {@link BluetoothQualityReport.BqrVsScoChoppy} object.
+ * <li> For Connect fail event, you can call {@link #getBqrCommon} to get a
+ * {@link BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrVsCommon} to get a
+ * {@link BluetoothQualityReport.BqrVsCommon} object, and call {@link #getBqrVsConnectFail} to
+ * get a {@link BluetoothQualityReport.BqrVsConnectFail} object.
+ * </ul>
+ *
+ * @hide
+ */
+public final class BluetoothQualityReport implements Parcelable {
+ private static final String TAG = "BluetoothQualityReport";
+
+ public static final int QUALITY_REPORT_ID_MONITOR = 0x01;
+ public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02;
+ public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03;
+ public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04;
+ /* Vendor Specific Report IDs from 0x20 */
+ public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x20;
+
+ private String mAddr;
+ private int mLmpVer;
+ private int mLmpSubVer;
+ private int mManufacturerId;
+ private String mName;
+ private int mBluetoothClass;
+
+ private BqrCommon mBqrCommon;
+
+ private BqrVsCommon mBqrVsCommon;
+ private BqrVsLsto mBqrVsLsto;
+ private BqrVsA2dpChoppy mBqrVsA2dpChoppy;
+ private BqrVsScoChoppy mBqrVsScoChoppy;
+ private BqrVsConnectFail mBqrVsConnectFail;
+
+ enum PacketType {
+ INVALID, TYPE_ID, TYPE_NULL, TYPE_POLL, TYPE_FHS, TYPE_HV1, TYPE_HV2, TYPE_HV3,
+ TYPE_DV, TYPE_EV3, TYPE_EV4, TYPE_EV5, TYPE_2EV3, TYPE_2EV5, TYPE_3EV3, TYPE_3EV5,
+ TYPE_DM1, TYPE_DH1, TYPE_DM3, TYPE_DH3, TYPE_DM5, TYPE_DH5, TYPE_AUX1, TYPE_2DH1,
+ TYPE_2DH3, TYPE_2DH5, TYPE_3DH1, TYPE_3DH3, TYPE_3DH5;
+
+ private static PacketType[] sAllValues = values();
+
+ static PacketType fromOrdinal(int n) {
+ if (n < sAllValues.length) {
+ return sAllValues[n];
+ }
+ return INVALID;
+ }
+ }
+
+ enum ConnState {
+ CONN_IDLE(0x00), CONN_ACTIVE(0x81), CONN_HOLD(0x02), CONN_SNIFF_IDLE(0x03),
+ CONN_SNIFF_ACTIVE(0x84), CONN_SNIFF_MASTER_TRANSITION(0x85), CONN_PARK(0x06),
+ CONN_PARK_PEND(0x47), CONN_UNPARK_PEND(0x08), CONN_UNPARK_ACTIVE(0x89),
+ CONN_DISCONNECT_PENDING(0x4A), CONN_PAGING(0x0B), CONN_PAGE_SCAN(0x0C),
+ CONN_LOCAL_LOOPBACK(0x0D), CONN_LE_ACTIVE(0x0E), CONN_ANT_ACTIVE(0x0F),
+ CONN_TRIGGER_SCAN(0x10), CONN_RECONNECTING(0x11), CONN_SEMI_CONN(0x12);
+
+ private int mValue;
+ private static ConnState[] sAllStates = values();
+
+ private ConnState(int val) {
+ mValue = val;
+ }
+
+ public static String getName(int val) {
+ for (ConnState state: sAllStates) {
+ if (state.mValue == val) {
+ return state.toString();
+ }
+ }
+ return "INVALID";
+ }
+ }
+
+ enum LinkQuality {
+ ULTRA_HIGH, HIGH, STANDARD, MEDIUM, LOW, INVALID;
+
+ private static LinkQuality[] sAllValues = values();
+
+ static LinkQuality fromOrdinal(int n) {
+ if (n < sAllValues.length - 1) {
+ return sAllValues[n];
+ }
+ return INVALID;
+ }
+ }
+
+ enum AirMode {
+ uLaw, aLaw, CVSD, transparent_msbc, INVALID;
+
+ private static AirMode[] sAllValues = values();
+
+ static AirMode fromOrdinal(int n) {
+ if (n < sAllValues.length - 1) {
+ return sAllValues[n];
+ }
+ return INVALID;
+ }
+ }
+
+ public BluetoothQualityReport(String remoteAddr, int lmpVer, int lmpSubVer,
+ int manufacturerId, String remoteName, int remoteCoD, byte[] rawData) {
+ if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) {
+ Log.d(TAG, "remote addr is invalid");
+ mAddr = "00:00:00:00:00:00";
+ } else {
+ mAddr = remoteAddr;
+ }
+
+ mLmpVer = lmpVer;
+ mLmpSubVer = lmpSubVer;
+ mManufacturerId = manufacturerId;
+ if (remoteName == null) {
+ Log.d(TAG, "remote name is null");
+ mName = "";
+ } else {
+ mName = remoteName;
+ }
+ mBluetoothClass = remoteCoD;
+
+ mBqrCommon = new BqrCommon(rawData, 0);
+
+ mBqrVsCommon = new BqrVsCommon(rawData, BqrCommon.BQR_COMMON_LEN);
+ int id = mBqrCommon.getQualityReportId();
+ if (id == QUALITY_REPORT_ID_MONITOR)
+ return;
+
+ int vsPartOffset = BqrCommon.BQR_COMMON_LEN + mBqrVsCommon.getLength();
+ if (id == QUALITY_REPORT_ID_APPROACH_LSTO) {
+ mBqrVsLsto = new BqrVsLsto(rawData, vsPartOffset);
+ } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) {
+ mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(rawData, vsPartOffset);
+ } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) {
+ mBqrVsScoChoppy = new BqrVsScoChoppy(rawData, vsPartOffset);
+ } else if (id == QUALITY_REPORT_ID_CONN_FAIL) {
+ mBqrVsConnectFail = new BqrVsConnectFail(rawData, vsPartOffset);
+ } else {
+ throw new IllegalArgumentException(TAG + ": unkown quality report id:" + id);
+ }
+ }
+
+ private BluetoothQualityReport(Parcel in) {
+ mBqrCommon = new BqrCommon(in);
+ mAddr = in.readString();
+ mLmpVer = in.readInt();
+ mLmpSubVer = in.readInt();
+ mManufacturerId = in.readInt();
+ mName = in.readString();
+ mBluetoothClass = in.readInt();
+
+ mBqrVsCommon = new BqrVsCommon(in);
+ int id = mBqrCommon.getQualityReportId();
+ if (id == QUALITY_REPORT_ID_APPROACH_LSTO) {
+ mBqrVsLsto = new BqrVsLsto(in);
+ } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) {
+ mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(in);
+ } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) {
+ mBqrVsScoChoppy = new BqrVsScoChoppy(in);
+ } else if (id == QUALITY_REPORT_ID_CONN_FAIL) {
+ mBqrVsConnectFail = new BqrVsConnectFail(in);
+ }
+ }
+
+ /**
+ * Get the quality report id.
+ * @return the id, is one of {@link #QUALITY_REPORT_ID_MONITOR},
+ * {@link #QUALITY_REPORT_ID_APPROACH_LSTO}, {@link #QUALITY_REPORT_ID_A2DP_CHOPPY},
+ * {@link #QUALITY_REPORT_ID_SCO_CHOPPY}, {@link #QUALITY_REPORT_ID_CONN_FAIL}.
+ */
+ public int getQualityReportId() {
+ return mBqrCommon.getQualityReportId();
+ }
+
+ /**
+ * Get the string of the quality report id.
+ * @return the string of the id.
+ */
+ public String getQualityReportIdStr() {
+ int id = mBqrCommon.getQualityReportId();
+ switch (id) {
+ case QUALITY_REPORT_ID_MONITOR:
+ return "Quality monitor";
+ case QUALITY_REPORT_ID_APPROACH_LSTO:
+ return "Approaching LSTO";
+ case QUALITY_REPORT_ID_A2DP_CHOPPY:
+ return "A2DP choppy";
+ case QUALITY_REPORT_ID_SCO_CHOPPY:
+ return "SCO choppy";
+ case QUALITY_REPORT_ID_CONN_FAIL:
+ return "Connect fail";
+ default:
+ return "INVALID";
+ }
+ }
+
+ /**
+ * Get bluetooth address of remote device in this report.
+ * @return bluetooth address of remote device.
+ */
+ public String getAddress() {
+ return mAddr;
+ }
+
+ /**
+ * Get LMP version of remote device in this report.
+ * @return LMP version of remote device.
+ */
+ public int getLmpVersion() {
+ return mLmpVer;
+ }
+
+ /**
+ * Get LMP subVersion of remote device in this report.
+ * @return LMP subVersion of remote device.
+ */
+ public int getLmpSubVersion() {
+ return mLmpSubVer;
+ }
+
+ /**
+ * Get manufacturer id of remote device in this report.
+ * @return manufacturer id of remote device.
+ */
+ public int getManufacturerId() {
+ return mManufacturerId;
+ }
+
+ /**
+ * Get the name of remote device in this report.
+ * @return the name of remote device.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Get the class of remote device in this report.
+ * @return the class of remote device.
+ */
+ public int getBluetoothClass() {
+ return mBluetoothClass;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrCommon} object.
+ * @return the {@link BluetoothQualityReport.BqrCommon} object.
+ */
+ public BqrCommon getBqrCommon() {
+ return mBqrCommon;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrVsCommon} object.
+ * @return the {@link BluetoothQualityReport.BqrVsCommon} object.
+ */
+ public BqrVsCommon getBqrVsCommon() {
+ return mBqrVsCommon;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrVsLsto} object.
+ * @return the {@link BluetoothQualityReport.BqrVsLsto} object
+ * or null if report id is not {@link #QUALITY_REPORT_ID_APPROACH_LSTO}.
+ */
+ public BqrVsLsto getBqrVsLsto() {
+ return mBqrVsLsto;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrVsA2dpChoppy} object.
+ * @return the {@link BluetoothQualityReport.BqrVsA2dpChoppy} object
+ * or null if report id is not {@link #QUALITY_REPORT_ID_A2DP_CHOPPY}.
+ */
+ public BqrVsA2dpChoppy getBqrVsA2dpChoppy() {
+ return mBqrVsA2dpChoppy;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrVsScoChoppy} object.
+ * @return the {@link BluetoothQualityReport.BqrVsScoChoppy} object
+ * or null if report id is not {@link #QUALITY_REPORT_ID_SCO_CHOPPY}.
+ */
+ public BqrVsScoChoppy getBqrVsScoChoppy() {
+ return mBqrVsScoChoppy;
+ }
+
+ /**
+ * Get the {@link BluetoothQualityReport.BqrVsConnectFail} object.
+ * @return the {@link BluetoothQualityReport.BqrVsConnectFail} object
+ * or null if report id is not {@link #QUALITY_REPORT_ID_CONN_FAIL}.
+ */
+ public BqrVsConnectFail getBqrVsConnectFail() {
+ return mBqrVsConnectFail;
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<BluetoothQualityReport> CREATOR =
+ new Parcelable.Creator<BluetoothQualityReport>() {
+ public BluetoothQualityReport createFromParcel(Parcel in) {
+ return new BluetoothQualityReport(in);
+ }
+
+ public BluetoothQualityReport[] newArray(int size) {
+ return new BluetoothQualityReport[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ mBqrCommon.writeToParcel(out, flags);
+ out.writeString(mAddr);
+ out.writeInt(mLmpVer);
+ out.writeInt(mLmpSubVer);
+ out.writeInt(mManufacturerId);
+ out.writeString(mName);
+ out.writeInt(mBluetoothClass);
+ mBqrVsCommon.writeToParcel(out, flags);
+ int id = mBqrCommon.getQualityReportId();
+ if (id == QUALITY_REPORT_ID_APPROACH_LSTO) {
+ mBqrVsLsto.writeToParcel(out, flags);
+ } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) {
+ mBqrVsA2dpChoppy.writeToParcel(out, flags);
+ } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) {
+ mBqrVsScoChoppy.writeToParcel(out, flags);
+ } else if (id == QUALITY_REPORT_ID_CONN_FAIL) {
+ mBqrVsConnectFail.writeToParcel(out, flags);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = "BQR: {\n"
+ + " mAddr: " + mAddr
+ + ", mLmpVer: " + String.format("0x%02X", mLmpVer)
+ + ", mLmpSubVer: " + String.format("0x%04X", mLmpSubVer)
+ + ", mManufacturerId: " + String.format("0x%04X", mManufacturerId)
+ + ", mName: " + mName
+ + ", mBluetoothClass: " + String.format("0x%X", mBluetoothClass)
+ + ",\n"
+ + mBqrCommon + "\n"
+ + mBqrVsCommon + "\n";
+
+ int id = mBqrCommon.getQualityReportId();
+ if (id == QUALITY_REPORT_ID_APPROACH_LSTO) {
+ str += mBqrVsLsto + "\n}";
+ } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) {
+ str += mBqrVsA2dpChoppy + "\n}";
+ } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) {
+ str += mBqrVsScoChoppy + "\n}";
+ } else if (id == QUALITY_REPORT_ID_CONN_FAIL) {
+ str += mBqrVsConnectFail + "\n}";
+ } else if (id == QUALITY_REPORT_ID_MONITOR) {
+ str += "}";
+ }
+
+ return str;
+ }
+
+ /**
+ * This class provides the public APIs to access the common part of BQR event.
+ */
+ public class BqrCommon implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrCommon";
+ static final int BQR_COMMON_LEN = 48;
+
+ private int mQualityReportId;
+ private int mPacketType;
+ private int mConnectionHandle;
+ private int mConnectionRole;
+ private int mTxPowerLevel;
+ private int mRssi;
+ private int mSnr;
+ private int mUnusedAfhChannelCount;
+ private int mAfhSelectUnidealChannelCount;
+ private int mLsto;
+ private long mPiconetClock;
+ private long mRetransmissionCount;
+ private long mNoRxCount;
+ private long mNakCount;
+ private long mLastTxAckTimestamp;
+ private long mFlowOffCount;
+ private long mLastFlowOnTimestamp;
+ private long mOverflowCount;
+ private long mUnderflowCount;
+
+ private BqrCommon(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length < offset + BQR_COMMON_LEN) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mQualityReportId = bqrBuf.get() & 0xFF;
+ mPacketType = bqrBuf.get() & 0xFF;
+ mConnectionHandle = bqrBuf.getShort() & 0xFFFF;
+ mConnectionRole = bqrBuf.get() & 0xFF;
+ mTxPowerLevel = bqrBuf.get() & 0xFF;
+ mRssi = bqrBuf.get();
+ mSnr = bqrBuf.get();
+ mUnusedAfhChannelCount = bqrBuf.get() & 0xFF;
+ mAfhSelectUnidealChannelCount = bqrBuf.get() & 0xFF;
+ mLsto = bqrBuf.getShort() & 0xFFFF;
+ mPiconetClock = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mRetransmissionCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mNoRxCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mNakCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mFlowOffCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mLastFlowOnTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mOverflowCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mUnderflowCount = bqrBuf.getInt() & 0xFFFFFFFFL;
+ }
+
+ private BqrCommon(Parcel in) {
+ mQualityReportId = in.readInt();
+ mPacketType = in.readInt();
+ mConnectionHandle = in.readInt();
+ mConnectionRole = in.readInt();
+ mTxPowerLevel = in.readInt();
+ mRssi = in.readInt();
+ mSnr = in.readInt();
+ mUnusedAfhChannelCount = in.readInt();
+ mAfhSelectUnidealChannelCount = in.readInt();
+ mLsto = in.readInt();
+ mPiconetClock = in.readLong();
+ mRetransmissionCount = in.readLong();
+ mNoRxCount = in.readLong();
+ mNakCount = in.readLong();
+ mLastTxAckTimestamp = in.readLong();
+ mFlowOffCount = in.readLong();
+ mLastFlowOnTimestamp = in.readLong();
+ mOverflowCount = in.readLong();
+ mUnderflowCount = in.readLong();
+ }
+
+ int getQualityReportId() {
+ return mQualityReportId;
+ }
+
+ /**
+ * Get the packet type of the connection.
+ * @return the packet type.
+ */
+ public int getPacketType() {
+ return mPacketType;
+ }
+
+ /**
+ * Get the string of packet type
+ * @return the string of packet type.
+ */
+ public String getPacketTypeStr() {
+ PacketType type = PacketType.fromOrdinal(mPacketType);
+ return type.toString();
+ }
+
+ /**
+ * Get the connecton handle of the connection
+ * @return the connecton handle.
+ */
+ public int getConnectionHandle() {
+ return mConnectionHandle;
+ }
+
+ /**
+ * Get the connecton Role of the connection, "Master" or "Slave".
+ * @return the connecton Role.
+ */
+ public String getConnectionRole() {
+ if (mConnectionRole == 0) {
+ return "Master";
+ } else if (mConnectionRole == 1) {
+ return "Slave";
+ } else {
+ return "INVALID:" + mConnectionRole;
+ }
+ }
+
+ /**
+ * Get the current transmit power level for the connection.
+ * @return the TX power level.
+ */
+ public int getTxPowerLevel() {
+ return mTxPowerLevel;
+ }
+
+ /**
+ * Get the Received Signal Strength Indication (RSSI) value for the connection.
+ * @return the RSSI.
+ */
+ public int getRssi() {
+ return mRssi;
+ }
+
+ /**
+ * get the Signal-to-Noise Ratio (SNR) value for the connection.
+ * @return the SNR.
+ */
+ public int getSnr() {
+ return mSnr;
+ }
+
+ /**
+ * Get the number of unused channels in AFH_channel_map.
+ * @return the number of unused channels.
+ */
+ public int getUnusedAfhChannelCount() {
+ return mUnusedAfhChannelCount;
+ }
+
+ /**
+ * Get the number of the channels which are interfered and quality is
+ * bad but are still selected for AFH.
+ * @return the number of the selected unideal channels.
+ */
+ public int getAfhSelectUnidealChannelCount() {
+ return mAfhSelectUnidealChannelCount;
+ }
+
+ /**
+ * Get the current link supervision timeout setting.
+ * time_ms: N * 0.625 ms (1 slot).
+ * @return link supervision timeout value.
+ */
+ public int getLsto() {
+ return mLsto;
+ }
+
+ /**
+ * Get the piconet clock for the specified Connection_Handle.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the piconet clock.
+ */
+ public long getPiconetClock() {
+ return mPiconetClock;
+ }
+
+ /**
+ * Get the count of retransmission.
+ * @return the count of retransmission.
+ */
+ public long getRetransmissionCount() {
+ return mRetransmissionCount;
+ }
+
+ /**
+ * Get the count of no RX.
+ * @return the count of no RX.
+ */
+ public long getNoRxCount() {
+ return mNoRxCount;
+ }
+
+ /**
+ * Get the count of NAK(Negative Acknowledge).
+ * @return the count of NAK.
+ */
+ public long getNakCount() {
+ return mNakCount;
+ }
+
+ /**
+ * Get the timestamp of last TX ACK.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the timestamp of last TX ACK.
+ */
+ public long getLastTxAckTimestamp() {
+ return mLastTxAckTimestamp;
+ }
+
+ /**
+ * Get the count of flow-off.
+ * @return the count of flow-off.
+ */
+ public long getFlowOffCount() {
+ return mFlowOffCount;
+ }
+
+ /**
+ * Get the timestamp of last flow-on.
+ * @return the timestamp of last flow-on.
+ */
+ public long getLastFlowOnTimestamp() {
+ return mLastFlowOnTimestamp;
+ }
+
+ /**
+ * Get the buffer overflow count (how many bytes of TX data are dropped) since the
+ * last event.
+ * @return the buffer overflow count.
+ */
+ public long getOverflowCount() {
+ return mOverflowCount;
+ }
+
+ /**
+ * Get the buffer underflow count (in byte).
+ * @return the buffer underflow count.
+ */
+ public long getUnderflowCount() {
+ return mUnderflowCount;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mQualityReportId);
+ dest.writeInt(mPacketType);
+ dest.writeInt(mConnectionHandle);
+ dest.writeInt(mConnectionRole);
+ dest.writeInt(mTxPowerLevel);
+ dest.writeInt(mRssi);
+ dest.writeInt(mSnr);
+ dest.writeInt(mUnusedAfhChannelCount);
+ dest.writeInt(mAfhSelectUnidealChannelCount);
+ dest.writeInt(mLsto);
+ dest.writeLong(mPiconetClock);
+ dest.writeLong(mRetransmissionCount);
+ dest.writeLong(mNoRxCount);
+ dest.writeLong(mNakCount);
+ dest.writeLong(mLastTxAckTimestamp);
+ dest.writeLong(mFlowOffCount);
+ dest.writeLong(mLastFlowOnTimestamp);
+ dest.writeLong(mOverflowCount);
+ dest.writeLong(mUnderflowCount);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrCommon: {\n"
+ + " mQualityReportId: " + BluetoothQualityReport.this.getQualityReportIdStr()
+ + "(" + String.format("0x%02X", mQualityReportId) + ")"
+ + ", mPacketType: " + getPacketTypeStr()
+ + "(" + String.format("0x%02X", mPacketType) + ")"
+ + ", mConnectionHandle: " + String.format("0x%04X", mConnectionHandle)
+ + ", mConnectionRole: " + getConnectionRole() + "(" + mConnectionRole + ")"
+ + ", mTxPowerLevel: " + mTxPowerLevel
+ + ", mRssi: " + mRssi
+ + ", mSnr: " + mSnr
+ + ", mUnusedAfhChannelCount: " + mUnusedAfhChannelCount
+ + ",\n"
+ + " mAfhSelectUnidealChannelCount: " + mAfhSelectUnidealChannelCount
+ + ", mLsto: " + mLsto
+ + ", mPiconetClock: " + String.format("0x%08X", mPiconetClock)
+ + ", mRetransmissionCount: " + mRetransmissionCount
+ + ", mNoRxCount: " + mNoRxCount
+ + ", mNakCount: " + mNakCount
+ + ", mLastTxAckTimestamp: " + String.format("0x%08X", mLastTxAckTimestamp)
+ + ", mFlowOffCount: " + mFlowOffCount
+ + ",\n"
+ + " mLastFlowOnTimestamp: " + String.format("0x%08X", mLastFlowOnTimestamp)
+ + ", mOverflowCount: " + mOverflowCount
+ + ", mUnderflowCount: " + mUnderflowCount
+ + "\n }";
+
+ return str;
+ }
+
+ }
+
+ /**
+ * This class provides the public APIs to access the vendor specific common part of
+ * BQR event.
+ */
+ public class BqrVsCommon implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsCommon";
+ private static final int BQR_VS_COMMON_LEN = 6 + 1;
+
+ private String mAddr;
+ private int mCalFailedItemCount;
+
+ private BqrVsCommon(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length < offset + BQR_VS_COMMON_LEN) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mAddr = String.format("%02X:%02X:%02X:%02X:%02X:%02X", bqrBuf.get(offset+5),
+ bqrBuf.get(offset+4), bqrBuf.get(offset+3), bqrBuf.get(offset+2),
+ bqrBuf.get(offset+1), bqrBuf.get(offset+0));
+ bqrBuf.position(offset+6);
+ mCalFailedItemCount = bqrBuf.get() & 0xFF;
+ }
+
+ private BqrVsCommon(Parcel in) {
+ mAddr = in.readString();
+ mCalFailedItemCount = in.readInt();
+ }
+
+ /**
+ * Get the count of calibration failed items.
+ * @return the count of calibration failure.
+ */
+ public int getCalFailedItemCount() {
+ return mCalFailedItemCount;
+ }
+
+ int getLength() {
+ return BQR_VS_COMMON_LEN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mAddr);
+ dest.writeInt(mCalFailedItemCount);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrVsCommon: {\n"
+ + " mAddr: " + mAddr
+ + ", mCalFailedItemCount: " + mCalFailedItemCount
+ + "\n }";
+
+ return str;
+ }
+ }
+
+ /**
+ * This class provides the public APIs to access the vendor specific part of
+ * Approaching LSTO event.
+ */
+ public class BqrVsLsto implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsLsto";
+
+ private int mConnState;
+ private long mBasebandStats;
+ private long mSlotsUsed;
+ private int mCxmDenials;
+ private int mTxSkipped;
+ private int mRfLoss;
+ private long mNativeClock;
+ private long mLastTxAckTimestamp;
+
+ private BqrVsLsto(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length <= offset) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mConnState = bqrBuf.get() & 0xFF;
+ mBasebandStats = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mSlotsUsed = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mCxmDenials = bqrBuf.getShort() & 0xFFFF;
+ mTxSkipped = bqrBuf.getShort() & 0xFFFF;
+ mRfLoss = bqrBuf.getShort() & 0xFFFF;
+ mNativeClock = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL;
+ }
+
+ private BqrVsLsto(Parcel in) {
+ mConnState = in.readInt();
+ mBasebandStats = in.readLong();
+ mSlotsUsed = in.readLong();
+ mCxmDenials = in.readInt();
+ mTxSkipped = in.readInt();
+ mRfLoss = in.readInt();
+ mNativeClock = in.readLong();
+ mLastTxAckTimestamp = in.readLong();
+ }
+
+ /**
+ * Get the conn state of sco.
+ * @return the conn state.
+ */
+ public int getConnState() {
+ return mConnState;
+ }
+
+ /**
+ * Get the string of conn state of sco.
+ * @return the string of conn state.
+ */
+ public String getConnStateStr() {
+ return ConnState.getName(mConnState);
+ }
+
+ /**
+ * Get the baseband statistics.
+ * @return the baseband statistics.
+ */
+ public long getBasebandStats() {
+ return mBasebandStats;
+ }
+
+ /**
+ * Get the count of slots allocated for current connection.
+ * @return the count of slots allocated for current connection.
+ */
+ public long getSlotsUsed() {
+ return mSlotsUsed;
+ }
+
+ /**
+ * Get the count of Coex denials.
+ * @return the count of CXM denials.
+ */
+ public int getCxmDenials() {
+ return mCxmDenials;
+ }
+
+ /**
+ * Get the count of TX skipped when no poll from remote device.
+ * @return the count of TX skipped.
+ */
+ public int getTxSkipped() {
+ return mTxSkipped;
+ }
+
+ /**
+ * Get the count of RF loss.
+ * @return the count of RF loss.
+ */
+ public int getRfLoss() {
+ return mRfLoss;
+ }
+
+ /**
+ * Get the timestamp when issue happened.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the timestamp when issue happened.
+ */
+ public long getNativeClock() {
+ return mNativeClock;
+ }
+
+ /**
+ * Get the timestamp of last TX ACK.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the timestamp of last TX ACK.
+ */
+ public long getLastTxAckTimestamp() {
+ return mLastTxAckTimestamp;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mConnState);
+ dest.writeLong(mBasebandStats);
+ dest.writeLong(mSlotsUsed);
+ dest.writeInt(mCxmDenials);
+ dest.writeInt(mTxSkipped);
+ dest.writeInt(mRfLoss);
+ dest.writeLong(mNativeClock);
+ dest.writeLong(mLastTxAckTimestamp);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrVsLsto: {\n"
+ + " mConnState: " + getConnStateStr()
+ + "(" + String.format("0x%02X", mConnState) + ")"
+ + ", mBasebandStats: " + String.format("0x%08X", mBasebandStats)
+ + ", mSlotsUsed: " + mSlotsUsed
+ + ", mCxmDenials: " + mCxmDenials
+ + ", mTxSkipped: " + mTxSkipped
+ + ", mRfLoss: " + mRfLoss
+ + ", mNativeClock: " + String.format("0x%08X", mNativeClock)
+ + ", mLastTxAckTimestamp: " + String.format("0x%08X", mLastTxAckTimestamp)
+ + "\n }";
+
+ return str;
+ }
+ }
+
+ /**
+ * This class provides the public APIs to access the vendor specific part of
+ * A2dp choppy event.
+ */
+ public class BqrVsA2dpChoppy implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsA2dpChoppy";
+
+ private long mArrivalTime;
+ private long mScheduleTime;
+ private int mGlitchCount;
+ private int mTxCxmDenials;
+ private int mRxCxmDenials;
+ private int mAclTxQueueLength;
+ private int mLinkQuality;
+
+ private BqrVsA2dpChoppy(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length <= offset) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mArrivalTime = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mScheduleTime = bqrBuf.getInt() & 0xFFFFFFFFL;
+ mGlitchCount = bqrBuf.getShort() & 0xFFFF;
+ mTxCxmDenials = bqrBuf.getShort() & 0xFFFF;
+ mRxCxmDenials = bqrBuf.getShort() & 0xFFFF;
+ mAclTxQueueLength = bqrBuf.get() & 0xFF;
+ mLinkQuality = bqrBuf.get() & 0xFF;
+ }
+
+ private BqrVsA2dpChoppy(Parcel in) {
+ mArrivalTime = in.readLong();
+ mScheduleTime = in.readLong();
+ mGlitchCount = in.readInt();
+ mTxCxmDenials = in.readInt();
+ mRxCxmDenials = in.readInt();
+ mAclTxQueueLength = in.readInt();
+ mLinkQuality = in.readInt();
+ }
+
+ /**
+ * Get the timestamp of a2dp packet arrived.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the timestamp of a2dp packet arrived.
+ */
+ public long getArrivalTime() {
+ return mArrivalTime;
+ }
+
+ /**
+ * Get the timestamp of a2dp packet scheduled.
+ * time_ms: N * 0.3125 ms (1 Bluetooth Clock).
+ * @return the timestamp of a2dp packet scheduled.
+ */
+ public long getScheduleTime() {
+ return mScheduleTime;
+ }
+
+ /**
+ * Get the a2dp glitch count since the last event.
+ * @return the a2dp glitch count.
+ */
+ public int getGlitchCount() {
+ return mGlitchCount;
+ }
+
+ /**
+ * Get the count of Coex TX denials.
+ * @return the count of Coex TX denials.
+ */
+ public int getTxCxmDenials() {
+ return mTxCxmDenials;
+ }
+
+ /**
+ * Get the count of Coex RX denials.
+ * @return the count of Coex RX denials.
+ */
+ public int getRxCxmDenials() {
+ return mRxCxmDenials;
+ }
+
+ /**
+ * Get the ACL queue length which are pending TX in FW.
+ * @return the ACL queue length.
+ */
+ public int getAclTxQueueLength() {
+ return mAclTxQueueLength;
+ }
+
+ /**
+ * Get the link quality for the current connection.
+ * @return the link quality.
+ */
+ public int getLinkQuality() {
+ return mLinkQuality;
+ }
+
+ /**
+ * Get the string of link quality for the current connection.
+ * @return the string of link quality.
+ */
+ public String getLinkQualityStr() {
+ LinkQuality q = LinkQuality.fromOrdinal(mLinkQuality);
+ return q.toString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mArrivalTime);
+ dest.writeLong(mScheduleTime);
+ dest.writeInt(mGlitchCount);
+ dest.writeInt(mTxCxmDenials);
+ dest.writeInt(mRxCxmDenials);
+ dest.writeInt(mAclTxQueueLength);
+ dest.writeInt(mLinkQuality);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrVsA2dpChoppy: {\n"
+ + " mArrivalTime: " + String.format("0x%08X", mArrivalTime)
+ + ", mScheduleTime: " + String.format("0x%08X", mScheduleTime)
+ + ", mGlitchCount: " + mGlitchCount
+ + ", mTxCxmDenials: " + mTxCxmDenials
+ + ", mRxCxmDenials: " + mRxCxmDenials
+ + ", mAclTxQueueLength: " + mAclTxQueueLength
+ + ", mLinkQuality: " + getLinkQualityStr()
+ + "(" + String.format("0x%02X", mLinkQuality) + ")"
+ + "\n }";
+
+ return str;
+ }
+
+ }
+
+ /**
+ * This class provides the public APIs to access the vendor specific part of
+ * SCO choppy event.
+ */
+ public class BqrVsScoChoppy implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsScoChoppy";
+
+ private int mGlitchCount;
+ private int mIntervalEsco;
+ private int mWindowEsco;
+ private int mAirFormat;
+ private int mInstanceCount;
+ private int mTxCxmDenials;
+ private int mRxCxmDenials;
+ private int mTxAbortCount;
+ private int mLateDispatch;
+ private int mMicIntrMiss;
+ private int mLpaIntrMiss;
+ private int mSprIntrMiss;
+ private int mPlcFillCount;
+ private int mPlcDiscardCount;
+
+ private BqrVsScoChoppy(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length <= offset) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mGlitchCount = bqrBuf.getShort() & 0xFFFF;
+ mIntervalEsco = bqrBuf.get() & 0xFF;
+ mWindowEsco = bqrBuf.get() & 0xFF;
+ mAirFormat = bqrBuf.get() & 0xFF;
+ mInstanceCount = bqrBuf.getShort() & 0xFFFF;
+ mTxCxmDenials = bqrBuf.getShort() & 0xFFFF;
+ mRxCxmDenials = bqrBuf.getShort() & 0xFFFF;
+ mTxAbortCount = bqrBuf.getShort() & 0xFFFF;
+ mLateDispatch = bqrBuf.getShort() & 0xFFFF;
+ mMicIntrMiss = bqrBuf.getShort() & 0xFFFF;
+ mLpaIntrMiss = bqrBuf.getShort() & 0xFFFF;
+ mSprIntrMiss = bqrBuf.getShort() & 0xFFFF;
+ mPlcFillCount = bqrBuf.getShort() & 0xFFFF;
+ mPlcDiscardCount = bqrBuf.getShort() & 0xFFFF;
+ }
+
+ private BqrVsScoChoppy(Parcel in) {
+ mGlitchCount = in.readInt();
+ mIntervalEsco = in.readInt();
+ mWindowEsco = in.readInt();
+ mAirFormat = in.readInt();
+ mInstanceCount = in.readInt();
+ mTxCxmDenials = in.readInt();
+ mRxCxmDenials = in.readInt();
+ mTxAbortCount = in.readInt();
+ mLateDispatch = in.readInt();
+ mMicIntrMiss = in.readInt();
+ mLpaIntrMiss = in.readInt();
+ mSprIntrMiss = in.readInt();
+ mPlcFillCount = in.readInt();
+ mPlcDiscardCount = in.readInt();
+ }
+
+ /**
+ * Get the sco glitch count since the last event.
+ * @return the sco glitch count.
+ */
+ public int getGlitchCount() {
+ return mGlitchCount;
+ }
+
+ /**
+ * Get ESCO interval in slots. It is the value of Transmission_Interval parameter in
+ * Synchronous Connection Complete event.
+ * @return ESCO interval in slots.
+ */
+ public int getIntervalEsco() {
+ return mIntervalEsco;
+ }
+
+ /**
+ * Get ESCO window in slots. It is the value of Retransmission Window parameter in
+ * Synchronous Connection Complete event.
+ * @return ESCO window in slots.
+ */
+ public int getWindowEsco() {
+ return mWindowEsco;
+ }
+
+ /**
+ * Get the air mode. It is the value of Air Mode parameter in
+ * Synchronous Connection Complete event.
+ * @return the air mode.
+ */
+ public int getAirFormat() {
+ return mAirFormat;
+ }
+
+ /**
+ * Get the string of air mode.
+ * @return the string of air mode.
+ */
+ public String getAirFormatStr() {
+ AirMode m = AirMode.fromOrdinal(mAirFormat);
+ return m.toString();
+ }
+
+ /**
+ * Get the xSCO instance count.
+ * @return the xSCO instance count.
+ */
+ public int getInstanceCount() {
+ return mInstanceCount;
+ }
+
+ /**
+ * Get the count of Coex TX denials.
+ * @return the count of Coex TX denials.
+ */
+ public int getTxCxmDenials() {
+ return mTxCxmDenials;
+ }
+
+ /**
+ * Get the count of Coex RX denials.
+ * @return the count of Coex RX denials.
+ */
+ public int getRxCxmDenials() {
+ return mRxCxmDenials;
+ }
+
+ /**
+ * Get the count of sco packets aborted.
+ * @return the count of sco packets aborted.
+ */
+ public int getTxAbortCount() {
+ return mTxAbortCount;
+ }
+
+ /**
+ * Get the count of sco packets dispatched late.
+ * @return the count of sco packets dispatched late.
+ */
+ public int getLateDispatch() {
+ return mLateDispatch;
+ }
+
+ /**
+ * Get the count of missed Mic interrrupts.
+ * @return the count of missed Mic interrrupts.
+ */
+ public int getMicIntrMiss() {
+ return mMicIntrMiss;
+ }
+
+ /**
+ * Get the count of missed LPA interrrupts.
+ * @return the count of missed LPA interrrupts.
+ */
+ public int getLpaIntrMiss() {
+ return mLpaIntrMiss;
+ }
+
+ /**
+ * Get the count of missed Speaker interrrupts.
+ * @return the count of missed Speaker interrrupts.
+ */
+ public int getSprIntrMiss() {
+ return mSprIntrMiss;
+ }
+
+ /**
+ * Get the count of packet loss concealment filled.
+ * @return the count of packet loss concealment filled.
+ */
+ public int getPlcFillCount() {
+ return mPlcFillCount;
+ }
+
+ /**
+ * Get the count of packet loss concealment discarded.
+ * @return the count of packet loss concealment discarded.
+ */
+ public int getPlcDiscardCount() {
+ return mPlcDiscardCount;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mGlitchCount);
+ dest.writeInt(mIntervalEsco);
+ dest.writeInt(mWindowEsco);
+ dest.writeInt(mAirFormat);
+ dest.writeInt(mInstanceCount);
+ dest.writeInt(mTxCxmDenials);
+ dest.writeInt(mRxCxmDenials);
+ dest.writeInt(mTxAbortCount);
+ dest.writeInt(mLateDispatch);
+ dest.writeInt(mMicIntrMiss);
+ dest.writeInt(mLpaIntrMiss);
+ dest.writeInt(mSprIntrMiss);
+ dest.writeInt(mPlcFillCount);
+ dest.writeInt(mPlcDiscardCount);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrVsScoChoppy: {\n"
+ + " mGlitchCount: " + mGlitchCount
+ + ", mIntervalEsco: " + mIntervalEsco
+ + ", mWindowEsco: " + mWindowEsco
+ + ", mAirFormat: " + getAirFormatStr()
+ + "(" + String.format("0x%02X", mAirFormat) + ")"
+ + ", mInstanceCount: " + mInstanceCount
+ + ", mTxCxmDenials: " + mTxCxmDenials
+ + ", mRxCxmDenials: " + mRxCxmDenials
+ + ", mTxAbortCount: " + mTxAbortCount
+ + ",\n"
+ + " mLateDispatch: " + mLateDispatch
+ + ", mMicIntrMiss: " + mMicIntrMiss
+ + ", mLpaIntrMiss: " + mLpaIntrMiss
+ + ", mSprIntrMiss: " + mSprIntrMiss
+ + ", mPlcFillCount: " + mPlcFillCount
+ + ", mPlcDiscardCount: " + mPlcDiscardCount
+ + "\n }";
+
+ return str;
+ }
+
+ }
+
+ /**
+ * This class provides the public APIs to access the vendor specific part of
+ * Connect fail event.
+ */
+ public class BqrVsConnectFail implements Parcelable {
+ private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsConnectFail";
+
+ private int mFailReason;
+
+ private BqrVsConnectFail(byte[] rawData, int offset) {
+ if (rawData == null || rawData.length <= offset) {
+ throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal.");
+ }
+
+ ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset)
+ .asReadOnlyBuffer();
+ bqrBuf.order(ByteOrder.LITTLE_ENDIAN);
+
+ mFailReason = bqrBuf.get() & 0xFF;
+ }
+
+ private BqrVsConnectFail(Parcel in) {
+ mFailReason = in.readInt();
+ }
+
+ /**
+ * Get the fail reason.
+ * @return the fail reason.
+ */
+ public int getFailReason() {
+ return mFailReason;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mFailReason);
+ }
+
+ @Override
+ public String toString() {
+ String str;
+ str = " BqrVsConnectFail: {\n"
+ + " mFailReason: " + String.format("0x%02X", mFailReason)
+ + "\n }";
+
+ return str;
+ }
+ }
+
+}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 760166b..e5d5c48 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -22,7 +22,6 @@
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
-
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -267,6 +266,7 @@
as.mSocketOS = as.mSocket.getOutputStream();
as.mAddress = remoteAddr;
as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
+ as.mPort = mPort;
return as;
}
@@ -788,5 +788,59 @@
return ret;
}
+ /**
+ * setSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @param optionLen socket option length
+ * @return -1 on immediate error,
+ * 0 otherwise
+ * @hide
+ */
+ public int setSocketOpt(int optionName, byte [] optionVal, int optionLen) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "setSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "setSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.setSocketOpt(mType, mPort, optionName, optionVal, optionLen);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
+
+ /**
+ * getSocketOpt for the Buetooth Socket.
+ *
+ * @param optionName socket option name
+ * @param optionVal socket option value
+ * @return -1 on immediate error,
+ * length of returned socket option otherwise
+ * @hide
+ */
+ public int getSocketOpt(int optionName, byte [] optionVal) throws IOException {
+ int ret = 0;
+ if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "getSocketOpt fail, reason: bluetooth is off");
+ return -1;
+ }
+ try {
+ if(VDBG) Log.d(TAG, "getSocketOpt(), mType: " + mType + " mPort: " + mPort);
+ ret = bluetoothProxy.getSocketOpt(mType, mPort, optionName, optionVal);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return -1;
+ }
+ return ret;
+ }
}
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index 5fd8258..d7f22bf 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -47,17 +47,20 @@
private final Map<ParcelUuid, byte[]> mServiceData;
private final boolean mIncludeTxPowerLevel;
private final boolean mIncludeDeviceName;
+ private final byte[] mTransportDiscoveryData;
private AdvertiseData(List<ParcelUuid> serviceUuids,
SparseArray<byte[]> manufacturerData,
Map<ParcelUuid, byte[]> serviceData,
boolean includeTxPowerLevel,
- boolean includeDeviceName) {
+ boolean includeDeviceName,
+ byte[] transportDiscoveryData) {
mServiceUuids = serviceUuids;
mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mIncludeTxPowerLevel = includeTxPowerLevel;
mIncludeDeviceName = includeDeviceName;
+ mTransportDiscoveryData = transportDiscoveryData;
}
/**
@@ -98,12 +101,20 @@
}
/**
+ * Returns an array of Transport Discovery data.
+ * @hide
+ */
+ public byte[] getTransportDiscoveryData() {
+ return mTransportDiscoveryData;
+ }
+
+ /**
* @hide
*/
@Override
public int hashCode() {
return Objects.hash(mServiceUuids, mManufacturerSpecificData, mServiceData,
- mIncludeDeviceName, mIncludeTxPowerLevel);
+ mIncludeDeviceName, mIncludeTxPowerLevel, mTransportDiscoveryData);
}
/**
@@ -123,7 +134,8 @@
other.mManufacturerSpecificData)
&& BluetoothLeUtils.equals(mServiceData, other.mServiceData)
&& mIncludeDeviceName == other.mIncludeDeviceName
- && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
+ && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel
+ && BluetoothLeUtils.equals(mTransportDiscoveryData, other.mTransportDiscoveryData);
}
@Override
@@ -132,7 +144,8 @@
+ BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData="
+ BluetoothLeUtils.toString(mServiceData)
+ ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
- + mIncludeDeviceName + "]";
+ + mIncludeDeviceName + ", mTransportDiscoveryData="
+ + BluetoothLeUtils.toString(mTransportDiscoveryData)+ "]";
}
@Override
@@ -157,6 +170,10 @@
}
dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
+ dest.writeInt(mTransportDiscoveryData != null ? mTransportDiscoveryData.length : 0);
+ if (mTransportDiscoveryData != null) {
+ dest.writeByteArray(mTransportDiscoveryData);
+ }
}
public static final @android.annotation.NonNull Parcelable.Creator<AdvertiseData> CREATOR =
@@ -188,6 +205,11 @@
}
builder.setIncludeTxPowerLevel(in.readByte() == 1);
builder.setIncludeDeviceName(in.readByte() == 1);
+ int transportDiscoveryDataSize = in.readInt();
+ if (transportDiscoveryDataSize > 0) {
+ byte[] transportDiscoveryData = in.createByteArray();
+ builder.addTransportDiscoveryData(transportDiscoveryData);
+ }
return builder.build();
}
};
@@ -202,6 +224,7 @@
private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
private boolean mIncludeTxPowerLevel;
private boolean mIncludeDeviceName;
+ private byte[] mTransportDiscoveryData;
/**
* Add a service UUID to advertise data.
@@ -276,11 +299,23 @@
}
/**
+ * Add Transport Discovery data
+ * @hide
+ */
+ public Builder addTransportDiscoveryData(byte[] transportDiscoveryData) {
+ if ((transportDiscoveryData == null) || (transportDiscoveryData.length == 0)) {
+ throw new IllegalArgumentException("transportDiscoveryData is null");
+ }
+ mTransportDiscoveryData = transportDiscoveryData;
+ return this;
+ }
+
+ /**
* Build the {@link AdvertiseData}.
*/
public AdvertiseData build() {
return new AdvertiseData(mServiceUuids, mManufacturerSpecificData, mServiceData,
- mIncludeTxPowerLevel, mIncludeDeviceName);
+ mIncludeTxPowerLevel, mIncludeDeviceName, mTransportDiscoveryData);
}
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index ac126ae..440d047 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -33,6 +33,7 @@
import android.os.WorkSource;
import android.util.Log;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -228,6 +229,13 @@
if (gatt == null) {
return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
}
+
+ if ((settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_SENSOR_ROUTING)
+ && (filters == null || filters.isEmpty())) {
+ ScanFilter filter = (new ScanFilter.Builder()).build();
+ filters = Arrays.asList(filter);
+ }
+
if (!isSettingsConfigAllowedForScan(settings)) {
return postCallbackErrorOrReturn(callback,
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
@@ -240,6 +248,10 @@
return postCallbackErrorOrReturn(callback,
ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
}
+ if (!isRoutingAllowedForScan(settings)) {
+ return postCallbackErrorOrReturn(callback,
+ ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
+ }
if (callback != null) {
BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
settings, workSource, callback, resultStorages);
@@ -599,4 +611,14 @@
}
return true;
}
+
+ private boolean isRoutingAllowedForScan(ScanSettings settings) {
+ final int callbackType = settings.getCallbackType();
+
+ if (callbackType == ScanSettings.CALLBACK_TYPE_SENSOR_ROUTING
+ && settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java
index 6381f55..f8d1c51 100644
--- a/core/java/android/bluetooth/le/BluetoothLeUtils.java
+++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java
@@ -77,6 +77,28 @@
}
/**
+ * Returns a string composed from a byte array.
+ */
+ static <T> String toString(byte[] data) {
+ if (data == null) {
+ return "null";
+ }
+ if (data.length == 0) {
+ return "{}";
+ }
+ StringBuilder buffer = new StringBuilder();
+ buffer.append('{');
+ for(int i=0; i < data.length; i++) {
+ buffer.append(data[i]);
+ if ((i+1) < data.length) {
+ buffer.append(", ");
+ }
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
* Check whether two {@link SparseArray} equal.
*/
static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
@@ -126,6 +148,25 @@
}
/**
+ * Check whether two byte arrays are equal.
+ */
+ static <T> boolean equals(byte[] data, byte[] otherData) {
+ if (data == otherData) {
+ return true;
+ }
+ if (data == null || otherData == null) {
+ return false;
+ }
+ if (data.length != otherData.length) {
+ return false;
+ }
+ if (!Objects.deepEquals(data, otherData)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Ensure Bluetooth is turned on.
*
* @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 038994f..6b680fd 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -47,6 +47,12 @@
*/
public final class ScanFilter implements Parcelable {
+ /**
+ * Provide TDS data scan results for WiFi Alliance Org id
+ * @hide
+ */
+ public static final int WIFI_ALLIANCE_ORG_ID = 2;
+
@Nullable
private final String mDeviceName;
@@ -76,6 +82,11 @@
@Nullable
private final byte[] mManufacturerDataMask;
+ private final int mOrgId;
+ private final int mTDSFlags;
+ private final int mTDSFlagsMask;
+ private final byte[] mWifiNANHash;
+
/** @hide */
public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
@@ -84,7 +95,8 @@
ParcelUuid uuidMask, ParcelUuid solicitationUuid,
ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
byte[] serviceData, byte[] serviceDataMask,
- int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) {
+ int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
+ int orgId, int TDSFlags, int TDSFlagsMask, byte[] wifiNANHash) {
mDeviceName = name;
mServiceUuid = uuid;
mServiceUuidMask = uuidMask;
@@ -97,6 +109,10 @@
mManufacturerId = manufacturerId;
mManufacturerData = manufacturerData;
mManufacturerDataMask = manufacturerDataMask;
+ mOrgId = orgId;
+ mTDSFlags = TDSFlags;
+ mTDSFlagsMask = TDSFlagsMask;
+ mWifiNANHash = wifiNANHash;
}
@Override
@@ -157,6 +173,17 @@
dest.writeByteArray(mManufacturerDataMask);
}
}
+ dest.writeInt(mOrgId);
+ dest.writeInt(mOrgId < 0 ? 0 : 1);
+ if(mOrgId >= 0) {
+ dest.writeInt(mTDSFlags);
+ dest.writeInt(mTDSFlagsMask);
+ dest.writeInt(mWifiNANHash == null ? 0 : 1);
+ if (mWifiNANHash != null) {
+ dest.writeInt(mWifiNANHash.length);
+ dest.writeByteArray(mWifiNANHash);
+ }
+ }
}
/**
@@ -234,6 +261,22 @@
}
}
+ int orgId = in.readInt();
+ if(in.readInt() == 1) {
+ int tdsFlags = in.readInt();
+ int tdsFlagsMask = in.readInt();
+ if (in.readInt() == 1) {
+ int wifiNANHashLength = in.readInt();
+ byte[] wifiNanHash = new byte[wifiNANHashLength];
+ in.readByteArray(wifiNanHash);
+ builder.setTransportDiscoveryData(orgId, tdsFlags, tdsFlagsMask,
+ wifiNanHash);
+ }
+ else {
+ builder.setTransportDiscoveryData(orgId, tdsFlags, tdsFlagsMask, null);
+ }
+ }
+
return builder.build();
}
};
@@ -313,6 +356,37 @@
}
/**
+ * @hide
+ * Returns the organization id. -1 if the organization id is not set.
+ */
+ public int getOrgId() {
+ return mOrgId;
+ }
+
+ /**
+ * @hide
+ * Returns the TDS flags. -1 if TDS flags is not set.
+ */
+ public int getTDSFlags() {
+ return mTDSFlags;
+ }
+
+ /**
+ * @hide
+ * Returns the TDS flags mask. -1 if TDS flags mask is not set.
+ */
+ public int getTDSFlagsMask() {
+ return mTDSFlagsMask;
+ }
+
+ /**
+ * @hide
+ */
+ public byte[] getWifiNANHash() {
+ return mWifiNANHash;
+ }
+
+ /**
* Check if the scan filter matches a {@code scanResult}. A scan result is considered as a match
* if it matches all the field filters.
*/
@@ -369,6 +443,18 @@
return false;
}
}
+
+ //Transport Discovery data match
+ if(mOrgId >= 0) {
+ byte[] tdsData = scanRecord.getTDSData();
+ if ((tdsData != null) && (tdsData.length > 0)) {
+ if ((mOrgId != tdsData[0]) ||
+ ((mTDSFlags & mTDSFlagsMask) != (tdsData[1] & mTDSFlagsMask))) {
+ return false;
+ }
+ }
+ }
+
// All filters match.
return true;
}
@@ -463,7 +549,10 @@
+ Arrays.toString(mServiceData) + ", mServiceDataMask="
+ Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId
+ ", mManufacturerData=" + Arrays.toString(mManufacturerData)
- + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask) + "]";
+ + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask)
+ + ", mOrganizationId=" + mOrgId + ", mTDSFlags=" + mTDSFlags
+ + ", mTDSFlagsMask=" + mTDSFlagsMask
+ + ", mWifiNANHash=" + Arrays.toString(mWifiNANHash) +"]";
}
@Override
@@ -475,7 +564,8 @@
Arrays.hashCode(mServiceData),
Arrays.hashCode(mServiceDataMask),
mServiceUuid, mServiceUuidMask,
- mServiceSolicitationUuid, mServiceSolicitationUuidMask);
+ mServiceSolicitationUuid, mServiceSolicitationUuidMask,
+ mOrgId, mTDSFlags, mTDSFlagsMask, Arrays.hashCode(mWifiNANHash));
}
@Override
@@ -499,7 +589,11 @@
&& Objects.equals(mServiceUuidMask, other.mServiceUuidMask)
&& Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid)
&& Objects.equals(mServiceSolicitationUuidMask,
- other.mServiceSolicitationUuidMask);
+ other.mServiceSolicitationUuidMask)
+ && mOrgId == other.mOrgId
+ && mTDSFlags == other.mTDSFlags
+ && mTDSFlagsMask == other.mTDSFlagsMask
+ && Objects.deepEquals(mWifiNANHash, other.mWifiNANHash);
}
/**
@@ -533,6 +627,11 @@
private byte[] mManufacturerData;
private byte[] mManufacturerDataMask;
+ private int mOrgId = -1;
+ private int mTDSFlags = -1;
+ private int mTDSFlagsMask = -1;
+ private byte[] mWifiNANHash;
+
/**
* Set filter on device name.
*/
@@ -719,6 +818,27 @@
return this;
}
+
+ /**
+ * @hide
+ * Set filter on transport discovery data.
+ * @throws IllegalArgumentException If the {@code orgId} is invalid or {@code
+ * wifiNANhash} is not null while {@code orgId} is non-Wifi.
+ */
+ public Builder setTransportDiscoveryData(int orgId, int TDSFlags, int TDSFlagsMask,
+ byte[] wifiNANHash) {
+ if (orgId < 0) {
+ throw new IllegalArgumentException("invalid organization id");
+ }
+ if ((orgId != WIFI_ALLIANCE_ORG_ID) && (wifiNANHash != null)) {
+ throw new IllegalArgumentException("Wifi NAN Hash is not null for non-Wifi Org Id");
+ }
+ mOrgId = orgId;
+ mTDSFlags = TDSFlags;
+ mTDSFlagsMask = TDSFlagsMask;
+ mWifiNANHash = wifiNANHash;
+ return this;
+ }
/**
* Build {@link ScanFilter}.
*
@@ -729,7 +849,8 @@
mServiceUuid, mUuidMask, mServiceSolicitationUuid,
mServiceSolicitationUuidMask,
mServiceDataUuid, mServiceData, mServiceDataMask,
- mManufacturerId, mManufacturerData, mManufacturerDataMask);
+ mManufacturerId, mManufacturerData, mManufacturerDataMask,
+ mOrgId, mTDSFlags, mTDSFlagsMask, mWifiNANHash);
}
}
}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 30868bf..4d69696 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -56,6 +56,7 @@
private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F;
private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15;
private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
+ private static final int DATA_TYPE_TRANSPORT_DISCOVERY_DATA = 0x26;
// Flags of the advertising data.
private final int mAdvertiseFlags;
@@ -78,6 +79,9 @@
// Raw bytes of scan record.
private final byte[] mBytes;
+ // Transport Discovery data.
+ private final byte[] mTDSData;
+
/**
* Returns the advertising flags indicating the discoverable mode and capability of the device.
* Returns -1 if the flag field is not set.
@@ -162,6 +166,14 @@
}
/**
+ * @hide
+ * Returns Transport Discovery data
+ */
+ public byte[] getTDSData() {
+ return mTDSData;
+ }
+
+ /**
* Returns raw bytes of scan record.
*/
public byte[] getBytes() {
@@ -173,7 +185,7 @@
SparseArray<byte[]> manufacturerData,
Map<ParcelUuid, byte[]> serviceData,
int advertiseFlags, int txPowerLevel,
- String localName, byte[] bytes) {
+ String localName, byte[] tdsData, byte[] bytes) {
mServiceSolicitationUuids = serviceSolicitationUuids;
mServiceUuids = serviceUuids;
mManufacturerSpecificData = manufacturerData;
@@ -181,6 +193,7 @@
mDeviceName = localName;
mAdvertiseFlags = advertiseFlags;
mTxPowerLevel = txPowerLevel;
+ mTDSData = tdsData;
mBytes = bytes;
}
@@ -211,6 +224,8 @@
SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
+ byte[] tdsData = null;
+
try {
while (currentPos < scanRecord.length) {
// length is unsigned int.
@@ -288,6 +303,9 @@
dataLength - 2);
manufacturerData.put(manufacturerId, manufacturerDataBytes);
break;
+ case DATA_TYPE_TRANSPORT_DISCOVERY_DATA:
+ tdsData = extractBytes(scanRecord, currentPos, dataLength);
+ break;
default:
// Just ignore, we don't handle such data type.
break;
@@ -299,12 +317,12 @@
serviceUuids = null;
}
return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData,
- serviceData, advertiseFlag, txPowerLevel, localName, scanRecord);
+ serviceData, advertiseFlag, txPowerLevel, localName, tdsData, scanRecord);
} catch (Exception e) {
Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
// As the record is invalid, ignore all the parsed results for this packet
// and return an empty record with raw scanRecord bytes in results
- return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
+ return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, null, scanRecord);
}
}
@@ -315,7 +333,8 @@
+ ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(
mManufacturerSpecificData)
+ ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
- + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
+ + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName +
+ ", mTDSData=" + BluetoothLeUtils.toString(mTDSData) +"]";
}
// Parse service UUIDs.
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 504118e..bd6e9d5 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -69,6 +69,12 @@
*/
public static final int CALLBACK_TYPE_MATCH_LOST = 4;
+ /**
+ * Provide results to sensor router instead of the apps processor
+ * @hide
+ */
+ public static final int CALLBACK_TYPE_SENSOR_ROUTING = 8;
+
/**
* Determines how many advertisements to match per filter, as this is scarce hw resource
@@ -302,7 +308,8 @@
private boolean isValidCallbackType(int callbackType) {
if (callbackType == CALLBACK_TYPE_ALL_MATCHES
|| callbackType == CALLBACK_TYPE_FIRST_MATCH
- || callbackType == CALLBACK_TYPE_MATCH_LOST) {
+ || callbackType == CALLBACK_TYPE_MATCH_LOST
+ || callbackType == CALLBACK_TYPE_SENSOR_ROUTING) {
return true;
}
return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7f9ea76..607a4ed 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -860,6 +860,7 @@
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
+ android.util.SeempLog.record_uri(13, uri);
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
@@ -942,6 +943,7 @@
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
+ android.util.SeempLog.record_uri(13, uri);
Preconditions.checkNotNull(uri, "uri");
try {
@@ -1856,6 +1858,7 @@
@Override
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@Nullable ContentValues values) {
+ android.util.SeempLog.record_uri(37, url);
Preconditions.checkNotNull(url, "url");
try {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4e7e713..44adbb9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2698,6 +2698,18 @@
public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
/**
+ * Broadcast Action: Sent to the optional package verifier when a package
+ * needs to be verified. The data contains the package URI.
+ * <p class="note">
+ * This is a protected intent.
+ * </p>
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_NEEDS_OPTIONAL_VERIFICATION = "com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION";
+
+ /**
* Broadcast Action: Sent to the system package verifier when a package is
* verified. The data contains the package URI.
* <p class="note">
@@ -10855,6 +10867,7 @@
case ACTION_MEDIA_SCANNER_FINISHED:
case ACTION_MEDIA_SCANNER_SCAN_FILE:
case ACTION_PACKAGE_NEEDS_VERIFICATION:
+ case ACTION_PACKAGE_NEEDS_OPTIONAL_VERIFICATION:
case ACTION_PACKAGE_VERIFIED:
case ACTION_PACKAGE_ENABLE_ROLLBACK:
// Ignore legacy actions
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d0a61eb..c5ae343 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -29,6 +29,8 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Environment;
+import android.os.SystemProperties;
+import android.util.DisplayMetrics;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -56,60 +58,60 @@
* <application> tag.
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
-
+
/**
- * Default task affinity of all activities in this application. See
- * {@link ActivityInfo#taskAffinity} for more information. This comes
- * from the "taskAffinity" attribute.
+ * Default task affinity of all activities in this application. See
+ * {@link ActivityInfo#taskAffinity} for more information. This comes
+ * from the "taskAffinity" attribute.
*/
public String taskAffinity;
-
+
/**
* Optional name of a permission required to be able to access this
* application's components. From the "permission" attribute.
*/
public String permission;
-
+
/**
* The name of the process this application should run in. From the
* "process" attribute or, if not set, the same as
* <var>packageName</var>.
*/
public String processName;
-
+
/**
* Class implementing the Application object. From the "class"
* attribute.
*/
public String className;
-
+
/**
* A style resource identifier (in the package's resources) of the
* description of an application. From the "description" attribute
* or, if not set, 0.
*/
- public int descriptionRes;
-
+ public int descriptionRes;
+
/**
* A style resource identifier (in the package's resources) of the
* default visual theme of the application. From the "theme" attribute
* or, if not set, 0.
*/
public int theme;
-
+
/**
* Class implementing the Application's manage space
* functionality. From the "manageSpaceActivity"
* attribute. This is an optional attribute and will be null if
* applications don't specify it in their manifest
*/
- public String manageSpaceActivityName;
-
+ public String manageSpaceActivityName;
+
/**
* Class implementing the Application's backup functionality. From
* the "backupAgent" attribute. This is an optional attribute and
* will be null if the application does not specify it in its manifest.
- *
+ *
* <p>If android:allowBackup is set to false, this attribute is ignored.
*/
public String backupAgentName;
@@ -144,7 +146,7 @@
* device's system image.
*/
public static final int FLAG_SYSTEM = 1<<0;
-
+
/**
* Value for {@link #flags}: set to true if this application would like to
* allow debugging of its
@@ -153,7 +155,7 @@
* android:debuggable} of the <application> tag.
*/
public static final int FLAG_DEBUGGABLE = 1<<1;
-
+
/**
* Value for {@link #flags}: set to true if this application has code
* associated with it. Comes
@@ -161,7 +163,7 @@
* android:hasCode} of the <application> tag.
*/
public static final int FLAG_HAS_CODE = 1<<2;
-
+
/**
* Value for {@link #flags}: set to true if this application is persistent.
* Comes from {@link android.R.styleable#AndroidManifestApplication_persistent
@@ -182,20 +184,20 @@
* android:allowTaskReparenting} of the <application> tag.
*/
public static final int FLAG_ALLOW_TASK_REPARENTING = 1<<5;
-
+
/**
* Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
* Comes from {@link android.R.styleable#AndroidManifestApplication_allowClearUserData
* android:allowClearUserData} of the <application> tag.
*/
public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
-
+
/**
* Value for {@link #flags}: this is set if this application has been
* installed as an update to a built-in system application.
*/
public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
-
+
/**
* Value for {@link #flags}: this is set if the application has specified
* {@link android.R.styleable#AndroidManifestApplication_testOnly
@@ -210,15 +212,15 @@
* android:smallScreens}.
*/
public static final int FLAG_SUPPORTS_SMALL_SCREENS = 1<<9;
-
+
/**
* Value for {@link #flags}: true when the application's window can be
* displayed on normal screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_normalScreens
* android:normalScreens}.
*/
- public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
-
+ public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
+
/**
* Value for {@link #flags}: true when the application's window can be
* increased in size for larger screens. Corresponds to
@@ -226,7 +228,7 @@
* android:largeScreens}.
*/
public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
-
+
/**
* Value for {@link #flags}: true when the application knows how to adjust
* its UI for different screen sizes. Corresponds to
@@ -234,7 +236,7 @@
* android:resizeable}.
*/
public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12;
-
+
/**
* Value for {@link #flags}: true when the application knows how to
* accommodate different screen densities. Corresponds to
@@ -242,7 +244,7 @@
* android:anyDensity}.
*/
public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
-
+
/**
* Value for {@link #flags}: set to true if this application would like to
* request the VM to operate under the safe mode. Comes from
@@ -254,7 +256,7 @@
/**
* Value for {@link #flags}: set to <code>false</code> if the application does not wish
* to permit any OS-driven backups of its data; <code>true</code> otherwise.
- *
+ *
* <p>Comes from the
* {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
* attribute of the <application> tag.
@@ -317,7 +319,7 @@
* android:xlargeScreens}.
*/
public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
-
+
/**
* Value for {@link #flags}: true when the application has requested a
* large heap for its processes. Corresponds to
@@ -742,6 +744,19 @@
public static final String METADATA_PRELOADED_FONTS = "preloaded_fonts";
/**
+ * Boolean indicating whether the resolution of the SurfaceView associated
+ * with this appplication can be overriden.
+ * {@hide}
+ */
+ public int overrideRes = 0;
+
+ /**
+ * In case, app needs different density than device density, set this value.
+ * {@hide}
+ */
+ public int overrideDensity = 0;
+
+ /**
* The required smallest screen width the application can run on. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
@@ -1002,7 +1017,7 @@
* the same uid).
*/
public int uid;
-
+
/**
* The minimum SDK version this application can run on. It will not run
* on earlier versions.
@@ -1523,7 +1538,7 @@
if (sb == null) {
sb = ab.packageName;
}
-
+
return sCollator.compare(sa.toString(), sb.toString());
}
@@ -1535,7 +1550,7 @@
public ApplicationInfo() {
}
-
+
public ApplicationInfo(ApplicationInfo orig) {
super(orig);
taskAffinity = orig.taskAffinity;
@@ -1545,6 +1560,8 @@
theme = orig.theme;
flags = orig.flags;
privateFlags = orig.privateFlags;
+ overrideRes = orig.overrideRes;
+ overrideDensity = orig.overrideDensity;
requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -1619,6 +1636,8 @@
dest.writeInt(theme);
dest.writeInt(flags);
dest.writeInt(privateFlags);
+ dest.writeInt(overrideRes);
+ dest.writeInt(overrideDensity);
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
@@ -1698,6 +1717,8 @@
theme = source.readInt();
flags = source.readInt();
privateFlags = source.readInt();
+ overrideRes = source.readInt();
+ overrideDensity = source.readInt();
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
@@ -1777,7 +1798,7 @@
/**
* Disable compatibility mode
- *
+ *
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -1935,7 +1956,7 @@
}
return pm.getDefaultActivityIcon();
}
-
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean isPackageUnavailable(PackageManager pm) {
try {
@@ -2115,12 +2136,18 @@
return output.toArray(new String[output.size()]);
}
+ /** @hide */
+ public int getOverrideDensity() {
+ return overrideDensity;
+ }
+
/** {@hide} */ public void setCodePath(String codePath) { scanSourceDir = codePath; }
/** {@hide} */ public void setBaseCodePath(String baseCodePath) { sourceDir = baseCodePath; }
/** {@hide} */ public void setSplitCodePaths(String[] splitCodePaths) { splitSourceDirs = splitCodePaths; }
/** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
/** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
/** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
+ /** {@hide} */ public void setOverrideRes(int overrideResolution) { overrideRes = overrideResolution; }
/** {@hide} */
@UnsupportedAppUsage
@@ -2132,4 +2159,5 @@
@UnsupportedAppUsage
public String getBaseResourcePath() { return publicSourceDir; }
/** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; }
+ /** {@hide} */ public int canOverrideRes() { return overrideRes; }
}
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index f3b7553..ad3eba9 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -30,6 +30,7 @@
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.util.Log;
/**
* CompatibilityInfo class keeps the information about the screen compatibility mode that the
@@ -43,6 +44,8 @@
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo() {
};
+ static final String TAG = "CompatibilityInfo";
+
/**
* This is the number of pixels we would like to have along the
* short axis of an app that needs to run on a normal size screen.
@@ -148,11 +151,18 @@
// Let the user decide.
compatFlags |= NEEDS_SCREEN_COMPAT;
}
-
- // Modern apps always support densities.
- applicationDensity = DisplayMetrics.DENSITY_DEVICE;
- applicationScale = 1.0f;
- applicationInvertedScale = 1.0f;
+ int density = appInfo.getOverrideDensity();
+ if(density != 0) {
+ applicationDensity = density;
+ applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) applicationDensity;
+ applicationInvertedScale = 1.0f / applicationScale;
+ compatFlags |= SCALING_REQUIRED;
+ } else {
+ // Modern apps always support densities.
+ applicationDensity = DisplayMetrics.DENSITY_DEVICE;
+ applicationScale = 1.0f;
+ applicationInvertedScale = 1.0f;
+ }
} else {
/**
@@ -239,20 +249,30 @@
compatFlags |= NEVER_NEEDS_COMPAT;
}
- if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
- applicationDensity = DisplayMetrics.DENSITY_DEVICE;
- applicationScale = 1.0f;
- applicationInvertedScale = 1.0f;
- } else {
+ int density = appInfo.getOverrideDensity();
+ if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) == 0) {
applicationDensity = DisplayMetrics.DENSITY_DEFAULT;
applicationScale = DisplayMetrics.DENSITY_DEVICE
/ (float) DisplayMetrics.DENSITY_DEFAULT;
applicationInvertedScale = 1.0f / applicationScale;
compatFlags |= SCALING_REQUIRED;
+ } else if(density != 0) {
+ applicationDensity = density;
+ applicationScale = DisplayMetrics.DENSITY_DEVICE / (float) applicationDensity;
+ applicationInvertedScale = 1.0f / applicationScale;
+ compatFlags |= SCALING_REQUIRED;
+ } else {
+ applicationDensity = DisplayMetrics.DENSITY_DEVICE;
+ applicationScale = 1.0f;
+ applicationInvertedScale = 1.0f;
}
}
mCompatibilityFlags = compatFlags;
+
+ Log.d(TAG, "mCompatibilityFlags - " + Integer.toHexString(mCompatibilityFlags));
+ Log.d(TAG, "applicationDensity - " + applicationDensity);
+ Log.d(TAG, "applicationScale - " + applicationScale);
}
private CompatibilityInfo(int compFlags,
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8e8a81d..8f012e4 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -39,6 +39,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSIllegalArgumentException;
@@ -48,6 +49,7 @@
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
+import android.os.SystemProperties;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
@@ -165,6 +167,10 @@
private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
private static final int CAMERA_MSG_FOCUS_MOVE = 0x800;
+ /* ### QC ADD-ONS: START */
+ private static final int CAMERA_MSG_STATS_DATA = 0x1000;
+ private static final int CAMERA_MSG_META_DATA = 0x2000;
+ /* ### QC ADD-ONS: END */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private long mNativeContext; // accessed by native methods
@@ -196,6 +202,17 @@
private boolean mShutterSoundEnabledFromApp = true;
private static final int NO_ERROR = 0;
+ private static final int EACCESS = -13;
+ private static final int ENODEV = -19;
+ private static final int EBUSY = -16;
+ private static final int EINVAL = -22;
+ private static final int ENOSYS = -38;
+ private static final int EUSERS = -87;
+ private static final int EOPNOTSUPP = -95;
+ /* ### QC ADD-ONS: START */
+ private CameraDataCallback mCameraDataCallback;
+ private CameraMetaDataCallback mCameraMetaDataCallback;
+ /* ### QC ADD-ONS: END */
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -277,7 +294,35 @@
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
*/
- public native static int getNumberOfCameras();
+ public static int getNumberOfCameras() {
+ boolean exposeAuxCamera = false;
+ String packageName = ActivityThread.currentOpPackageName();
+ /* Force to expose only two cameras
+ * if the package name does not falls in this bucket
+ */
+ String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ exposeAuxCamera = true;
+ break;
+ }
+ }
+ }
+ int numberOfCameras = _getNumberOfCameras();
+ if (exposeAuxCamera == false && (numberOfCameras > 2)) {
+ numberOfCameras = 2;
+ }
+ return numberOfCameras;
+ }
+
+ /**
+ * Returns the number of physical cameras available on this device.
+ */
+ /** @hide */
+ public native static int _getNumberOfCameras();
/**
* Returns the information about a particular camera.
@@ -288,6 +333,9 @@
* low-level failure).
*/
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
+ if(cameraId >= getNumberOfCameras()){
+ throw new RuntimeException("Unknown camera ID");
+ }
_getCameraInfo(cameraId, cameraInfo);
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
IAudioService audioService = IAudioService.Stub.asInterface(b);
@@ -321,6 +369,17 @@
*/
public static final int CAMERA_FACING_FRONT = 1;
+ /* ### QC ADD-ONS: START TBD*/
+ /** @hide
+ * camera is in ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_ZSL = 2;
+
+ /** @hide
+ * camera is in non-ZSL mode.
+ */
+ public static final int CAMERA_SUPPORT_MODE_NONZSL = 3;
+ /* ### QC ADD-ONS: END */
/**
* The direction that the camera faces. It should be
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
@@ -507,6 +566,10 @@
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
+ /* ### QC ADD-ONS: START */
+ mCameraDataCallback = null;
+ mCameraMetaDataCallback = null;
+ /* ### QC ADD-ONS: END */
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -517,8 +580,21 @@
mEventHandler = null;
}
- return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
- ActivityThread.currentOpPackageName());
+ String packageName = ActivityThread.currentOpPackageName();
+
+ //Force HAL1 if the package name falls in this bucket
+ String packageList = SystemProperties.get("vendor.camera.hal1.packagelist", "");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ halVersion = CAMERA_HAL_API_VERSION_1_0;
+ break;
+ }
+ }
+ }
+ return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}
private int cameraInitNormal(int cameraId) {
@@ -545,6 +621,9 @@
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId) {
+ if(cameraId >= getNumberOfCameras()){
+ throw new RuntimeException("Unknown camera ID");
+ }
int err = cameraInitNormal(cameraId);
if (checkInitErrors(err)) {
if (err == -EACCES) {
@@ -870,6 +949,7 @@
* @see android.media.MediaActionSound
*/
public final void setPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(66);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = false;
@@ -898,6 +978,7 @@
* @see android.media.MediaActionSound
*/
public final void setOneShotPreviewCallback(PreviewCallback cb) {
+ android.util.SeempLog.record(68);
mPreviewCallback = cb;
mOneShot = true;
mWithBuffer = false;
@@ -938,6 +1019,7 @@
* @see android.media.MediaActionSound
*/
public final void setPreviewCallbackWithBuffer(PreviewCallback cb) {
+ android.util.SeempLog.record(67);
mPreviewCallback = cb;
mOneShot = false;
mWithBuffer = true;
@@ -1269,7 +1351,23 @@
mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
}
return;
+ /* ### QC ADD-ONS: START */
+ case CAMERA_MSG_STATS_DATA:
+ int statsdata[] = new int[257];
+ for(int i =0; i<257; i++ ) {
+ statsdata[i] = byteToInt( (byte[])msg.obj, i*4);
+ }
+ if (mCameraDataCallback != null) {
+ mCameraDataCallback.onCameraData(statsdata, mCamera);
+ }
+ return;
+ case CAMERA_MSG_META_DATA:
+ if (mCameraMetaDataCallback != null) {
+ mCameraMetaDataCallback.onCameraMetaData((byte[])msg.obj, mCamera);
+ }
+ return;
+ /* ### QC ADD-ONS: END */
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
@@ -1503,6 +1601,7 @@
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
takePicture(shutter, raw, null, jpeg);
}
private native final void native_takePicture(int msgType);
@@ -1541,6 +1640,7 @@
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
+ android.util.SeempLog.record(65);
mShutterCallback = shutter;
mRawImageCallback = raw;
mPostviewCallback = postview;
@@ -2010,6 +2110,23 @@
* as a set. Either they are all valid, or none of them are.
*/
public Point mouth = null;
+
+ /**
+ * {@hide}
+ */
+ public int smileDegree = 0;
+ /**
+ * {@hide}
+ */
+ public int smileScore = 0;
+ /**
+ * {@hide}
+ */
+ public int blinkDetected = 0;
+ /**
+ * {@hide}
+ */
+ public int faceRecognised = 0;
}
/**
@@ -2134,6 +2251,27 @@
return p;
}
+ /** @hide
+ * Returns the current cct value of white balance.
+ *
+ * If it's in AWB mode, cct is determined by stats/awb module.
+ *
+ * If it's in Manual WB mode, it actually returns cct value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getWBCurrentCCT() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int cct = 0;
+ if (p.getWBCurrentCCT() != null) {
+ cct = Integer.parseInt(p.getWBCurrentCCT());
+ }
+
+ return cct;
+ }
+
/**
* Returns an empty {@link Parameters} for testing purpose.
*
@@ -2147,6 +2285,157 @@
return camera.new Parameters();
}
+ /* ### QC ADD-ONS: START */
+ private static int byteToInt(byte[] b, int offset) {
+ int value = 0;
+ for (int i = 0; i < 4; i++) {
+ int shift = (4 - 1 - i) * 8;
+ value += (b[(3-i) + offset] & 0x000000FF) << shift;
+ }
+ return value;
+ }
+ /** @hide
+ * Handles the callback for when Camera Data is available.
+ * data is read from the camera.
+ */
+ public interface CameraDataCallback {
+ /**
+ * Callback for when camera data is available.
+ *
+ * @param data a int array of the camera data
+ * @param camera the Camera service object
+ */
+ void onCameraData(int[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera histogram mode and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setHistogramMode(CameraDataCallback cb)
+ {
+ mCameraDataCallback = cb;
+ native_setHistogramMode(cb!=null);
+ }
+ private native final void native_setHistogramMode(boolean mode);
+
+ /** @hide
+ * Set camera histogram command to send data.
+ *
+ */
+ public final void sendHistogramData()
+ {
+ native_sendHistogramData();
+ }
+ private native final void native_sendHistogramData();
+
+ /** @hide
+ * Handles the callback for when Camera Meta Data is available.
+ * Meta data is read from the camera.
+ */
+ public interface CameraMetaDataCallback {
+ /**
+ * Callback for when camera meta data is available.
+ *
+ * @param data a byte array of the camera meta data
+ * @param camera the Camera service object
+ */
+ void onCameraMetaData(byte[] data, Camera camera);
+ };
+
+ /** @hide
+ * Set camera meta data and registers a callback function to run.
+ * Only valid after startPreview() has been called.
+ *
+ * @param cb the callback to run
+ */
+ public final void setMetadataCb(CameraMetaDataCallback cb)
+ {
+ mCameraMetaDataCallback = cb;
+ native_setMetadataCb(cb!=null);
+ }
+ private native final void native_setMetadataCb(boolean mode);
+
+ /** @hide
+ * Set camera face detection command to send meta data.
+ */
+ public final void sendMetaData()
+ {
+ native_sendMetaData();
+ }
+ private native final void native_sendMetaData();
+
+ /** @hide
+ * Configure longshot mode. Available only in ZSL.
+ *
+ * @param enable enable/disable this mode
+ */
+ public final void setLongshot(boolean enable)
+ {
+ native_setLongshot(enable);
+ }
+ private native final void native_setLongshot(boolean enable);
+
+ /** @hide
+ * Handles the Touch Co-ordinate.
+ */
+ public class Coordinate {
+ /**
+ * Sets the x,y co-ordinates for a touch event
+ *
+ * @param x the x co-ordinate (pixels)
+ * @param y the y co-ordinate (pixels)
+ */
+ public Coordinate(int x, int y) {
+ xCoordinate = x;
+ yCoordinate = y;
+ }
+ /**
+ * Compares {@code obj} to this co-ordinate.
+ *
+ * @param obj the object to compare this co-ordinate with.
+ * @return {@code true} if the xCoordinate and yCoordinate of {@code obj} is the
+ * same as those of this coordinate. {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Coordinate)) {
+ return false;
+ }
+ Coordinate c = (Coordinate) obj;
+ return xCoordinate == c.xCoordinate && yCoordinate == c.yCoordinate;
+ }
+
+ /** x co-ordinate for the touch event*/
+ public int xCoordinate;
+
+ /** y co-ordinate for the touch event */
+ public int yCoordinate;
+ };
+
+ /** @hide
+ * Returns the current focus position.
+ *
+ * If it's in AF mode, it's the lens position after af is done.
+ *
+ * If it's in Manual Focus mode, it actually returns the value
+ * set by user via {@link #setParameters(Camera.Parameters)}.
+ */
+ public int getCurrentFocusPosition() {
+ Parameters p = new Parameters();
+ String s = native_getParameters();
+ p.unflatten(s);
+
+ int focus_pos = -1;
+ if (p.getCurrentFocusPosition() != null) {
+ focus_pos = Integer.parseInt(p.getCurrentFocusPosition());
+ }
+ return focus_pos;
+ }
+
+ /* ### QC ADD-ONS: END */
/**
* Returns a copied {@link Parameters}; for shim use only.
*
@@ -2408,6 +2697,10 @@
public static final String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight";
public static final String WHITE_BALANCE_TWILIGHT = "twilight";
public static final String WHITE_BALANCE_SHADE = "shade";
+ /** @hide
+ * wb manual cct mode.
+ */
+ public static final String WHITE_BALANCE_MANUAL_CCT = "manual-cct";
// Values for color effect settings.
public static final String EFFECT_NONE = "none";
@@ -2455,6 +2748,11 @@
*/
public static final String FLASH_MODE_TORCH = "torch";
+ /** @hide
+ * Scene mode is off.
+ */
+ public static final String SCENE_MODE_ASD = "asd";
+
/**
* Scene mode is off.
*/
@@ -2531,6 +2829,14 @@
* Capture the naturally warm color of scenes lit by candles.
*/
public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
+ /** @hide
+ * SCENE_MODE_BACKLIGHT
+ **/
+ public static final String SCENE_MODE_BACKLIGHT = "backlight";
+ /** @hide
+ * SCENE_MODE_FLOWERS
+ **/
+ public static final String SCENE_MODE_FLOWERS = "flowers";
/**
* Applications are looking for a barcode. Camera driver will be
@@ -2573,6 +2879,13 @@
*/
public static final String FOCUS_MODE_FIXED = "fixed";
+ /** @hide
+ * Normal focus mode. Applications should call
+ * {@link #autoFocus(AutoFocusCallback)} to start the focus in this
+ * mode.
+ */
+ public static final String FOCUS_MODE_NORMAL = "normal";
+
/**
* Extended depth of field (EDOF). Focusing is done digitally and
* continuously. Applications should not call {@link
@@ -2625,6 +2938,11 @@
*/
public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
+ /** @hide
+ * manual focus mode
+ */
+ public static final String FOCUS_MODE_MANUAL_POSITION = "manual";
+
// Indices for focus distance array.
/**
* The array index of near focus distance for use with
@@ -2661,11 +2979,15 @@
// Formats for setPreviewFormat and setPictureFormat.
private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
+ private static final String PIXEL_FORMAT_YUV420SP_ADRENO = "yuv420sp-adreno";
private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
private static final String PIXEL_FORMAT_YUV420P = "yuv420p";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb";
+ private static final String PIXEL_FORMAT_RAW = "raw";
+ private static final String PIXEL_FORMAT_YV12 = "yv12";
+ private static final String PIXEL_FORMAT_NV12 = "nv12";
/**
* Order matters: Keys that are {@link #set(String, String) set} later
@@ -3485,8 +3807,11 @@
* parameters.
*/
public void removeGpsData() {
+ remove(KEY_QC_GPS_LATITUDE_REF);
remove(KEY_GPS_LATITUDE);
+ remove(KEY_QC_GPS_LONGITUDE_REF);
remove(KEY_GPS_LONGITUDE);
+ remove(KEY_QC_GPS_ALTITUDE_REF);
remove(KEY_GPS_ALTITUDE);
remove(KEY_GPS_TIMESTAMP);
remove(KEY_GPS_PROCESSING_METHOD);
@@ -4510,5 +4835,1231 @@
if (s1 != null && s1.equals(s2)) return true;
return false;
}
+ /* ### QC ADD-ONS: START */
+
+ /* ### QC ADDED PARAMETER KEYS*/
+ private static final String KEY_QC_HFR_SIZE = "hfr-size";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_MODE = "preview-frame-rate-mode";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_AUTO_MODE = "frame-rate-auto";
+ private static final String KEY_QC_PREVIEW_FRAME_RATE_FIXED_MODE = "frame-rate-fixed";
+ private static final String KEY_QC_GPS_LATITUDE_REF = "gps-latitude-ref";
+ private static final String KEY_QC_GPS_LONGITUDE_REF = "gps-longitude-ref";
+ private static final String KEY_QC_GPS_ALTITUDE_REF = "gps-altitude-ref";
+ private static final String KEY_QC_GPS_STATUS = "gps-status";
+ private static final String KEY_QC_EXIF_DATETIME = "exif-datetime";
+ private static final String KEY_QC_TOUCH_AF_AEC = "touch-af-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AEC = "touch-index-aec";
+ private static final String KEY_QC_TOUCH_INDEX_AF = "touch-index-af";
+ private static final String KEY_QC_MANUAL_FOCUS_POSITION = "manual-focus-position";
+ private static final String KEY_QC_MANUAL_FOCUS_POS_TYPE = "manual-focus-pos-type";
+ private static final String KEY_QC_SCENE_DETECT = "scene-detect";
+ private static final String KEY_QC_ISO_MODE = "iso";
+ private static final String KEY_QC_EXPOSURE_TIME = "exposure-time";
+ private static final String KEY_QC_MIN_EXPOSURE_TIME = "min-exposure-time";
+ private static final String KEY_QC_MAX_EXPOSURE_TIME = "max-exposure-time";
+ private static final String KEY_QC_LENSSHADE = "lensshade";
+ private static final String KEY_QC_HISTOGRAM = "histogram";
+ private static final String KEY_QC_SKIN_TONE_ENHANCEMENT = "skinToneEnhancement";
+ private static final String KEY_QC_AUTO_EXPOSURE = "auto-exposure";
+ private static final String KEY_QC_SHARPNESS = "sharpness";
+ private static final String KEY_QC_MAX_SHARPNESS = "max-sharpness";
+ private static final String KEY_QC_CONTRAST = "contrast";
+ private static final String KEY_QC_MAX_CONTRAST = "max-contrast";
+ private static final String KEY_QC_SATURATION = "saturation";
+ private static final String KEY_QC_MAX_SATURATION = "max-saturation";
+ private static final String KEY_QC_DENOISE = "denoise";
+ private static final String KEY_QC_CONTINUOUS_AF = "continuous-af";
+ private static final String KEY_QC_SELECTABLE_ZONE_AF = "selectable-zone-af";
+ private static final String KEY_QC_FACE_DETECTION = "face-detection";
+ private static final String KEY_QC_MEMORY_COLOR_ENHANCEMENT = "mce";
+ private static final String KEY_QC_REDEYE_REDUCTION = "redeye-reduction";
+ private static final String KEY_QC_ZSL = "zsl";
+ private static final String KEY_QC_CAMERA_MODE = "camera-mode";
+ private static final String KEY_QC_VIDEO_HIGH_FRAME_RATE = "video-hfr";
+ private static final String KEY_QC_VIDEO_HDR = "video-hdr";
+ private static final String KEY_QC_POWER_MODE = "power-mode";
+ private static final String KEY_QC_POWER_MODE_SUPPORTED = "power-mode-supported";
+ private static final String KEY_QC_WB_MANUAL_CCT = "wb-manual-cct";
+ private static final String KEY_QC_MIN_WB_CCT = "min-wb-cct";
+ private static final String KEY_QC_MAX_WB_CCT = "max-wb-cct";
+ private static final String KEY_QC_AUTO_HDR_ENABLE = "auto-hdr-enable";
+ private static final String KEY_QC_VIDEO_ROTATION = "video-rotation";
+
+ /** @hide
+ * KEY_QC_AE_BRACKET_HDR
+ **/
+ public static final String KEY_QC_AE_BRACKET_HDR = "ae-bracket-hdr";
+
+ /* ### QC ADDED PARAMETER VALUES*/
+
+ // Values for touch af/aec settings.
+ /** @hide
+ * TOUCH_AF_AEC_OFF
+ **/
+ public static final String TOUCH_AF_AEC_OFF = "touch-off";
+ /** @hide
+ * TOUCH_AF_AEC_ON
+ **/
+ public static final String TOUCH_AF_AEC_ON = "touch-on";
+
+ // Values for auto exposure settings.
+ /** @hide
+ * Auto exposure frame-avg
+ **/
+ public static final String AUTO_EXPOSURE_FRAME_AVG = "frame-average";
+ /** @hide
+ * Auto exposure center weighted
+ **/
+ public static final String AUTO_EXPOSURE_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * Auto exposure spot metering
+ **/
+ public static final String AUTO_EXPOSURE_SPOT_METERING = "spot-metering";
+
+ //Values for ISO settings
+ /** @hide
+ * ISO_AUTO
+ **/
+ public static final String ISO_AUTO = "auto";
+ /** @hide
+ * ISO_HJR
+ **/
+ public static final String ISO_HJR = "ISO_HJR";
+ /** @hide
+ * ISO_100
+ **/
+ public static final String ISO_100 = "ISO100";
+ /** @hide
+ * ISO_200
+ **/
+ public static final String ISO_200 = "ISO200";
+ /** @hide
+ * ISO_400
+ **/
+ public static final String ISO_400 = "ISO400";
+ /** @hide
+ * ISO_800
+ **/
+ public static final String ISO_800 = "ISO800";
+ /** @hide
+ * ISO_1600
+ **/
+ public static final String ISO_1600 = "ISO1600";
+
+ /** @hide
+ * ISO_3200
+ **/
+ public static final String ISO_3200 = "ISO3200";
+
+ //Values for Lens Shading
+ /** @hide
+ * LENSSHADE_ENABLE
+ **/
+ public static final String LENSSHADE_ENABLE = "enable";
+ /** @hide
+ * LENSSHADE_DISABLE
+ **/
+ public static final String LENSSHADE_DISABLE= "disable";
+
+ //Values for Histogram
+ /** @hide
+ * Histogram enable
+ **/
+ public static final String HISTOGRAM_ENABLE = "enable";
+ /** @hide
+ * Histogram disable
+ **/
+ public static final String HISTOGRAM_DISABLE= "disable";
+
+ //Values for Skin Tone Enhancement
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_ENABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_ENABLE = "enable";
+ /** @hide
+ * SKIN_TONE_ENHANCEMENT_DISABLE
+ **/
+ public static final String SKIN_TONE_ENHANCEMENT_DISABLE= "disable";
+
+ // Values for MCE settings.
+ /** @hide
+ * MCE_ENaBLE
+ **/
+ public static final String MCE_ENABLE = "enable";
+ /** @hide
+ * MCE_DISABLE
+ **/
+ public static final String MCE_DISABLE = "disable";
+
+ // Values for ZSL settings.
+ /** @hide
+ * ZSL_ON
+ **/
+ public static final String ZSL_ON = "on";
+ /** @hide
+ * ZSL_OFF
+ **/
+ public static final String ZSL_OFF = "off";
+
+ // Values for HDR Bracketing settings.
+
+ /** @hide
+ * AEC bracketing off
+ **/
+ public static final String AE_BRACKET_HDR_OFF = "Off";
+ /** @hide
+ * AEC bracketing hdr
+ **/
+ public static final String AE_BRACKET_HDR = "HDR";
+ /** @hide
+ * AEC bracketing aec-bracket
+ **/
+ public static final String AE_BRACKET = "AE-Bracket";
+
+ // Values for Power mode.
+ /** @hide
+ * LOW_POWER
+ **/
+ public static final String LOW_POWER = "Low_Power";
+ /** @hide
+ * NORMAL_POWER
+ **/
+ public static final String NORMAL_POWER = "Normal_Power";
+
+ // Values for HFR settings.
+ /** @hide
+ * VIDEO_HFR_OFF
+ **/
+ public static final String VIDEO_HFR_OFF = "off";
+ /** @hide
+ * VIDEO_HFR_2X
+ **/
+ public static final String VIDEO_HFR_2X = "60";
+ /** @hide
+ * VIDEO_HFR_3X
+ **/
+ public static final String VIDEO_HFR_3X = "90";
+ /** @hide
+ * VIDEO_HFR_4X
+ **/
+ public static final String VIDEO_HFR_4X = "120";
+
+ // Values for auto scene detection settings.
+ /** @hide
+ * SCENE_DETECT_OFF
+ **/
+ public static final String SCENE_DETECT_OFF = "off";
+ /** @hide
+ * SCENE_DETECT_ON
+ **/
+ public static final String SCENE_DETECT_ON = "on";
+
+ //Values for Continuous AF
+
+ /** @hide
+ * CAF off
+ **/
+ public static final String CONTINUOUS_AF_OFF = "caf-off";
+ /** @hide
+ * CAF on
+ **/
+ public static final String CONTINUOUS_AF_ON = "caf-on";
+ /** @hide
+ * Denoise off
+ **/
+ public static final String DENOISE_OFF = "denoise-off";
+ /** @hide
+ * Denoise on
+ **/
+ public static final String DENOISE_ON = "denoise-on";
+
+ // Values for Redeye Reduction settings.
+ /** @hide
+ * REDEYE_REDUCTION_ENABLE
+ **/
+ public static final String REDEYE_REDUCTION_ENABLE = "enable";
+ /** @hide
+ * REDEYE_REDUCTION_DISABLE
+ **/
+ public static final String REDEYE_REDUCTION_DISABLE = "disable";
+
+ // Values for selectable zone af settings.
+ /** @hide
+ * SELECTABLE_ZONE_AF_AUTO
+ **/
+ public static final String SELECTABLE_ZONE_AF_AUTO = "auto";
+ /** @hide
+ * SELECTABLE_ZONE_AF_SPOTMETERING
+ **/
+ public static final String SELECTABLE_ZONE_AF_SPOTMETERING = "spot-metering";
+ /** @hide
+ * SELECTABLE_ZONE_AF_CENTER_WEIGHTED
+ **/
+ public static final String SELECTABLE_ZONE_AF_CENTER_WEIGHTED = "center-weighted";
+ /** @hide
+ * SELECTABLE_ZONE_AF_FRAME_AVERAGE
+ **/
+ public static final String SELECTABLE_ZONE_AF_FRAME_AVERAGE = "frame-average";
+
+ // Values for Face Detection settings.
+ /** @hide
+ * Face Detection off
+ **/
+ public static final String FACE_DETECTION_OFF = "off";
+ /** @hide
+ * Face Detction on
+ **/
+ public static final String FACE_DETECTION_ON = "on";
+
+ // Values for video rotation settings.
+
+ /** @hide
+ * VIDEO_ROTATION_0
+ **/
+ public static final String VIDEO_ROTATION_0 = "0";
+ /** @hide
+ * VIDEO_ROTATION_90
+ **/
+ public static final String VIDEO_ROTATION_90 = "90";
+ /** @hide
+ * VIDEO_ROTATION_180
+ **/
+ public static final String VIDEO_ROTATION_180 = "180";
+ /** @hide
+ * VIDEO_ROTATION_270
+ **/
+ public static final String VIDEO_ROTATION_270 = "270";
+
+ /* ### QC ADDED PARAMETER APIS*/
+ /** @hide
+ * Gets the supported preview sizes in high frame rate recording mode.
+ *
+ * @return a list of Size object. This method will always return a list
+ * with at least one element.
+ */
+ public List<Size> getSupportedHfrSizes() {
+ String str = get(KEY_QC_HFR_SIZE + SUPPORTED_VALUES_SUFFIX);
+ return splitSize(str);
+ }
+
+ /** @hide
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedTouchAfAec() {
+ String str = get(KEY_QC_TOUCH_AF_AEC + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /**
+ * Gets the supported Touch AF/AEC setting.
+ *
+ * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC
+ * setting is not supported.
+ *
+ */
+
+ /** @hide
+ * Gets the supported frame rate modes.
+ *
+ * @return a List of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedPreviewFrameRateModes() {
+ String str = get(KEY_QC_PREVIEW_FRAME_RATE_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto scene detection modes.
+ *
+ * @return a List of SCENE_DETECT_XXX string constant. null if scene detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedSceneDetectModes() {
+ String str = get(KEY_QC_SCENE_DETECT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ISO values.
+ *
+ * @return a List of FLASH_MODE_XXX string constants. null if flash mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedIsoValues() {
+ String str = get(KEY_QC_ISO_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Lensshade modes.
+ *
+ * @return a List of LENS_MODE_XXX string constants. null if lens mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedLensShadeModes() {
+ String str = get(KEY_QC_LENSSHADE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Histogram modes.
+ *
+ * @return a List of HISTOGRAM_XXX string constants. null if histogram mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedHistogramModes() {
+ String str = get(KEY_QC_HISTOGRAM + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Skin Tone Enhancement modes.
+ *
+ * @return a List of SKIN_TONE_ENHANCEMENT_XXX string constants. null if skin tone enhancement
+ * setting is not supported.
+ */
+ public List<String> getSupportedSkinToneEnhancementModes() {
+ String str = get(KEY_QC_SKIN_TONE_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported auto exposure setting.
+ *
+ * @return a List of AUTO_EXPOSURE_XXX string constants. null if auto exposure
+ * setting is not supported.
+ */
+ public List<String> getSupportedAutoexposure() {
+ String str = get(KEY_QC_AUTO_EXPOSURE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported MCE modes.
+ *
+ * @return a List of MCE_ENABLE/DISABLE string constants. null if MCE mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedMemColorEnhanceModes() {
+ String str = get(KEY_QC_MEMORY_COLOR_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported ZSL modes.
+ *
+ * @return a List of ZSL_OFF/OFF string constants. null if ZSL mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedZSLModes() {
+ String str = get(KEY_QC_ZSL + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Video HDR modes.
+ *
+ * @return a List of Video HDR_OFF/OFF string constants. null if
+ * Video HDR mode setting is not supported.
+ */
+ public List<String> getSupportedVideoHDRModes() {
+ String str = get(KEY_QC_VIDEO_HDR + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported HFR modes.
+ *
+ * @return a List of VIDEO_HFR_XXX string constants. null if hfr mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoHighFrameRateModes() {
+ String str = get(KEY_QC_VIDEO_HIGH_FRAME_RATE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported Continuous AF modes.
+ *
+ * @return a List of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedContinuousAfModes() {
+ String str = get(KEY_QC_CONTINUOUS_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported DENOISE modes.
+ *
+ * @return a List of DENOISE_XXX string constant. null if DENOISE
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedDenoiseModes() {
+ String str = get(KEY_QC_DENOISE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported selectable zone af setting.
+ *
+ * @return a List of SELECTABLE_ZONE_AF_XXX string constants. null if selectable zone af
+ * setting is not supported.
+ */
+ public List<String> getSupportedSelectableZoneAf() {
+ String str = get(KEY_QC_SELECTABLE_ZONE_AF + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported face detection modes.
+ *
+ * @return a List of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedFaceDetectionModes() {
+ String str = get(KEY_QC_FACE_DETECTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Gets the supported redeye reduction modes.
+ *
+ * @return a List of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public List<String> getSupportedRedeyeReductionModes() {
+ String str = get(KEY_QC_REDEYE_REDUCTION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ /** @hide
+ * Sets GPS altitude reference. This will be stored in JPEG EXIF header.
+ * @param altRef reference GPS altitude in meters.
+ */
+ public void setGpsAltitudeRef(double altRef) {
+ set(KEY_QC_GPS_ALTITUDE_REF, Double.toString(altRef));
+ }
+
+ /** @hide
+ * Sets GPS Status. This will be stored in JPEG EXIF header.
+ *
+ * @param status GPS status (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setGpsStatus(double status) {
+ set(KEY_QC_GPS_STATUS, Double.toString(status));
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AEC.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAec(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AEC, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAec() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AEC);
+ return strToCoordinate(pair);
+ }
+
+ /** @hide
+ * Sets the touch co-ordinate for Touch AF.
+ *
+ * @param x the x co-ordinate of the touch event
+ * @param y the y co-ordinate of the touch event
+ *
+ */
+ public void setTouchIndexAf(int x, int y) {
+ String v = Integer.toString(x) + "x" + Integer.toString(y);
+ set(KEY_QC_TOUCH_INDEX_AF, v);
+ }
+
+ /** @hide
+ * Returns the touch co-ordinates of the touch event.
+ *
+ * @return a Index object with the x and y co-ordinated
+ * for the touch event
+ *
+ */
+ public Coordinate getTouchIndexAf() {
+ String pair = get(KEY_QC_TOUCH_INDEX_AF);
+ return strToCoordinate(pair);
+ }
+ /** @hide
+ * Set Sharpness Level
+ *
+ * @param sharpness level
+ */
+ public void setSharpness(int sharpness){
+ if((sharpness < 0) || (sharpness > getMaxSharpness()) )
+ throw new IllegalArgumentException(
+ "Invalid Sharpness " + sharpness);
+
+ set(KEY_QC_SHARPNESS, String.valueOf(sharpness));
+ }
+
+ /** @hide
+ * Set Contrast Level
+ *
+ * @param contrast level
+ */
+ public void setContrast(int contrast){
+ if((contrast < 0 ) || (contrast > getMaxContrast()))
+ throw new IllegalArgumentException(
+ "Invalid Contrast " + contrast);
+
+ set(KEY_QC_CONTRAST, String.valueOf(contrast));
+ }
+
+ /** @hide
+ * Set Saturation Level
+ *
+ * @param saturation level
+ */
+ public void setSaturation(int saturation){
+ if((saturation < 0 ) || (saturation > getMaxSaturation()))
+ throw new IllegalArgumentException(
+ "Invalid Saturation " + saturation);
+
+ set(KEY_QC_SATURATION, String.valueOf(saturation));
+ }
+
+ /** @hide
+ * @return true if full size video snapshot is supported.
+ */
+ public boolean isPowerModeSupported() {
+ String str = get(KEY_QC_POWER_MODE_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
+ /** @hide
+ * Get Sharpness level
+ *
+ * @return sharpness level
+ */
+ public int getSharpness(){
+ return getInt(KEY_QC_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Max Sharpness Level
+ *
+ * @return max sharpness level
+ */
+ public int getMaxSharpness(){
+ return getInt(KEY_QC_MAX_SHARPNESS);
+ }
+
+ /** @hide
+ * Get Contrast level
+ *
+ * @return contrast level
+ */
+ public int getContrast(){
+ return getInt(KEY_QC_CONTRAST);
+ }
+
+ /** @hide
+ * Get Max Contrast Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxContrast(){
+ return getInt(KEY_QC_MAX_CONTRAST);
+ }
+
+ /** @hide
+ * Get Saturation level
+ *
+ * @return saturation level
+ */
+ public int getSaturation(){
+ return getInt(KEY_QC_SATURATION);
+ }
+
+ /** @hide
+ * Get Max Saturation Level
+ *
+ * @return max contrast level
+ */
+ public int getMaxSaturation(){
+ return getInt(KEY_QC_MAX_SATURATION);
+ }
+
+ /** @hide
+ * Sets GPS latitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param latRef GPS latitude reference coordinate.
+ */
+ public void setGpsLatitudeRef(String latRef) {
+ set(KEY_QC_GPS_LATITUDE_REF, latRef);
+ }
+
+ /** @hide
+ * Sets GPS longitude reference coordinate. This will be stored in JPEG EXIF
+ * header.
+ * @param lonRef GPS longitude reference coordinate.
+ */
+ public void setGpsLongitudeRef(String lonRef) {
+ set(KEY_QC_GPS_LONGITUDE_REF, lonRef);
+ }
+
+ /** @hide
+ * Sets system timestamp. This will be stored in JPEG EXIF header.
+ *
+ * @param dateTime current timestamp (UTC in seconds since January 1,
+ * 1970).
+ */
+ public void setExifDateTime(String dateTime) {
+ set(KEY_QC_EXIF_DATETIME, dateTime);
+ }
+
+ /** @hide
+ * Gets the current Touch AF/AEC setting.
+ *
+ * @return one of TOUCH_AF_AEC_XXX string constant. null if Touch AF/AEC
+ * setting is not supported.
+ *
+ */
+ public String getTouchAfAec() {
+ return get(KEY_QC_TOUCH_AF_AEC);
+ }
+
+ /** @hide
+ * Sets the current TOUCH AF/AEC setting.
+ *
+ * @param value TOUCH_AF_AEC_XXX string constants.
+ *
+ */
+ public void setTouchAfAec(String value) {
+ set(KEY_QC_TOUCH_AF_AEC, value);
+ }
+
+ /** @hide
+ * Gets the current redeye reduction setting.
+ *
+ * @return one of REDEYE_REDUCTION_XXX string constant. null if redeye reduction
+ * setting is not supported.
+ *
+ */
+ public String getRedeyeReductionMode() {
+ return get(KEY_QC_REDEYE_REDUCTION);
+ }
+
+ /** @hide
+ * Sets the redeye reduction. Other parameters may be changed after changing
+ * redeye reduction. After setting redeye reduction,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value REDEYE_REDUCTION_XXX string constants.
+ *
+ */
+ public void setRedeyeReductionMode(String value) {
+ set(KEY_QC_REDEYE_REDUCTION, value);
+ }
+
+ /** @hide
+ * Gets the frame rate mode setting.
+ *
+ * @return one of FRAME_RATE_XXX_MODE string constant. null if this
+ * setting is not supported.
+ */
+ public String getPreviewFrameRateMode() {
+ return get(KEY_QC_PREVIEW_FRAME_RATE_MODE);
+ }
+
+ /** @hide
+ * Sets the frame rate mode.
+ *
+ * @param value FRAME_RATE_XXX_MODE string constants.
+ */
+ public void setPreviewFrameRateMode(String value) {
+ set(KEY_QC_PREVIEW_FRAME_RATE_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current auto scene detection setting.
+ *
+ * @return one of SCENE_DETECT_XXX string constant. null if auto scene detection
+ * setting is not supported.
+ *
+ */
+ public String getSceneDetectMode() {
+ return get(KEY_QC_SCENE_DETECT);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other parameters may be changed after changing
+ * scene detect. After setting auto scene detection,
+ * applications should call getParameters to know if some parameters are
+ * changed.
+ *
+ * @param value SCENE_DETECT_XXX string constants.
+ *
+ */
+ public void setSceneDetectMode(String value) {
+ set(KEY_QC_SCENE_DETECT, value);
+ }
+
+ /** @hide
+ * Gets the current hdr bracketing mode setting.
+ *
+ * @return current hdr bracketing mode.
+ * @see #KEY_AE_BRACKET_OFF
+ * @see #KEY_AE_BRACKET_HDR
+ * @see #KEY_AE_BRACKET_BRACKATING
+ */
+ public String getAEBracket() {
+ return get(KEY_QC_AE_BRACKET_HDR);
+ }
+
+ /** @hide
+ * Sets the Power mode.
+ *
+ * @param value Power mode.
+ * @see #getPowerMode()
+ */
+ public void setPowerMode(String value) {
+ set(KEY_QC_POWER_MODE, value);
+ }
+
+ /** @hide
+ * Gets the current power mode setting.
+ *
+ * @return current power mode. null if power mode setting is not
+ * supported.
+ * @see #POWER_MODE_LOW
+ * @see #POWER_MODE_NORMAL
+ */
+ public String getPowerMode() {
+ return get(KEY_QC_POWER_MODE);
+ }
+
+ /** @hide
+ * Set HDR-Bracketing Level
+ *
+ * @param value HDR-Bracketing
+ */
+ public void setAEBracket(String value){
+ set(KEY_QC_AE_BRACKET_HDR, value);
+ }
+
+ /** @hide
+ * Gets the current ISO setting.
+ *
+ * @return one of ISO_XXX string constant. null if ISO
+ * setting is not supported.
+ */
+ public String getISOValue() {
+ return get(KEY_QC_ISO_MODE);
+ }
+
+ /** @hide
+ * Sets the ISO.
+ *
+ * @param iso ISO_XXX string constant.
+ */
+ public void setISOValue(String iso) {
+ set(KEY_QC_ISO_MODE, iso);
+ }
+
+ /** @hide
+ * Sets the exposure time.
+ *
+ * @param value exposure time.
+ */
+ public void setExposureTime(int value) {
+ set(KEY_QC_EXPOSURE_TIME, Integer.toString(value));
+ }
+
+ /** @hide
+ * Gets the current exposure time.
+ *
+ * @return exposure time.
+ */
+ public String getExposureTime() {
+ return get(KEY_QC_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the min supported exposure time.
+ *
+ * @return min supported exposure time.
+ */
+ public String getMinExposureTime() {
+ return get(KEY_QC_MIN_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the max supported exposure time.
+ *
+ * @return max supported exposure time.
+ */
+ public String getMaxExposureTime() {
+ return get(KEY_QC_MAX_EXPOSURE_TIME);
+ }
+
+ /** @hide
+ * Gets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public String getLensShade() {
+ return get(KEY_QC_LENSSHADE);
+ }
+
+ /** @hide
+ * Sets the current LensShade Mode.
+ *
+ * @return LensShade Mode
+ */
+ public void setLensShade(String lensshade) {
+ set(KEY_QC_LENSSHADE, lensshade);
+ }
+
+ /** @hide
+ * Gets the current auto exposure setting.
+ *
+ * @return one of AUTO_EXPOSURE_XXX string constant. null if auto exposure
+ * setting is not supported.
+ */
+ public String getAutoExposure() {
+ return get(KEY_QC_AUTO_EXPOSURE);
+ }
+
+ /** @hide
+ * Sets the current auto exposure setting.
+ *
+ * @param value AUTO_EXPOSURE_XXX string constants.
+ */
+ public void setAutoExposure(String value) {
+ set(KEY_QC_AUTO_EXPOSURE, value);
+ }
+
+ /** @hide
+ * Gets the current MCE Mode.
+ *
+ * @return MCE value
+ */
+ public String getMemColorEnhance() {
+ return get(KEY_QC_MEMORY_COLOR_ENHANCEMENT);
+ }
+
+ /** @hide
+ * Sets the current MCE Mode.
+ *
+ * @return MCE Mode
+ */
+ public void setMemColorEnhance(String mce) {
+ set(KEY_QC_MEMORY_COLOR_ENHANCEMENT, mce);
+ }
+
+ /** @hide
+ * Set white balance manual cct value.
+ *
+ * @param cct user CCT setting.
+ */
+ public void setWBManualCCT(int cct) {
+ set(KEY_QC_WB_MANUAL_CCT, Integer.toString(cct));
+ }
+
+ /** @hide
+ * Gets the WB min supported CCT.
+ *
+ * @return min cct value.
+ */
+ public String getWBMinCCT() {
+ return get(KEY_QC_MIN_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the WB max supported CCT.
+ *
+ * @return max cct value.
+ */
+ public String getMaxWBCCT() {
+ return get(KEY_QC_MAX_WB_CCT);
+ }
+
+ /** @hide
+ * Gets the current WB CCT.
+ *
+ * @return CCT value
+ */
+ public String getWBCurrentCCT() {
+ return get(KEY_QC_WB_MANUAL_CCT);
+ }
+
+ /** @hide
+ * Gets the current ZSL Mode.
+ *
+ * @return ZSL mode value
+ */
+ public String getZSLMode() {
+ return get(KEY_QC_ZSL);
+ }
+
+ /** @hide
+ * Sets the current ZSL Mode. ZSL mode is set as a 0th bit in KEY_CAMERA_MODE.
+ *
+ * @return null
+ */
+ public void setZSLMode(String zsl) {
+ set(KEY_QC_ZSL, zsl);
+ }
+
+ /** @hide
+ * Sets the current Auto HDR Mode.
+ * @ auto_hdr auto hdr string for enable/disable
+ * @return null
+ */
+ public void setAutoHDRMode(String auto_hdr){
+ set(KEY_QC_AUTO_HDR_ENABLE,auto_hdr);
+ }
+
+ /** @hide
+ * Gets the current Camera Mode Flag. Camera mode includes a
+ * flag(byte) which indicates different camera modes.
+ * For now support for ZSL added at bit0
+ *
+ * @return Camera Mode.
+ */
+ public String getCameraMode() {
+ return get(KEY_QC_CAMERA_MODE);
+ }
+
+ /** @hide
+ * Sets the current Camera Mode.
+ *
+ * @return null
+ */
+ public void setCameraMode(int cameraMode) {
+ set(KEY_QC_CAMERA_MODE, cameraMode);
+ }
+
+ private static final int MANUAL_FOCUS_POS_TYPE_INDEX = 0;
+ private static final int MANUAL_FOCUS_POS_TYPE_DAC = 1;
+ /** @hide
+ * Set focus position.
+ *
+ * @param pos user setting of focus position.
+ */
+ public void setFocusPosition(int type, int pos) {
+ set(KEY_QC_MANUAL_FOCUS_POS_TYPE, Integer.toString(type));
+ set(KEY_QC_MANUAL_FOCUS_POSITION, Integer.toString(pos));
+ }
+
+ /** @hide
+ * Gets the current focus position.
+ *
+ * @return current focus position
+ */
+ public String getCurrentFocusPosition() {
+ return get(KEY_QC_MANUAL_FOCUS_POSITION);
+ }
+
+
+ /** @hide
+ * Gets the current HFR Mode.
+ *
+ * @return VIDEO_HFR_XXX string constants
+ */
+ public String getVideoHighFrameRate() {
+ return get(KEY_QC_VIDEO_HIGH_FRAME_RATE);
+ }
+
+ /** @hide
+ * Sets the current HFR Mode.
+ *
+ * @param hfr VIDEO_HFR_XXX string constants
+ */
+ public void setVideoHighFrameRate(String hfr) {
+ set(KEY_QC_VIDEO_HIGH_FRAME_RATE, hfr);
+ }
+
+ /** @hide
+ * Gets the current Video HDR Mode.
+ *
+ * @return Video HDR mode value
+ */
+ public String getVideoHDRMode() {
+ return get(KEY_QC_VIDEO_HDR);
+ }
+
+ /** @hide
+ * Sets the current Video HDR Mode.
+ *
+ * @return null
+ */
+ public void setVideoHDRMode(String videohdr) {
+ set(KEY_QC_VIDEO_HDR, videohdr);
+ }
+
+ /** @hide
+ * Gets the current DENOISE setting.
+ *
+ * @return one of DENOISE_XXX string constant. null if Denoise
+ * setting is not supported.
+ *
+ */
+ public String getDenoise() {
+ return get(KEY_QC_DENOISE);
+ }
+
+ /** @hide
+ * Gets the current Continuous AF setting.
+ *
+ * @return one of CONTINUOUS_AF_XXX string constant. null if continuous AF
+ * setting is not supported.
+ *
+ */
+ public String getContinuousAf() {
+ return get(KEY_QC_CONTINUOUS_AF);
+ }
+
+ /** @hide
+ * Sets the current Denoise mode.
+ * @param value DENOISE_XXX string constants.
+ *
+ */
+
+ public void setDenoise(String value) {
+ set(KEY_QC_DENOISE, value);
+ }
+
+ /** @hide
+ * Sets the current Continuous AF mode.
+ * @param value CONTINUOUS_AF_XXX string constants.
+ *
+ */
+ public void setContinuousAf(String value) {
+ set(KEY_QC_CONTINUOUS_AF, value);
+ }
+
+ /** @hide
+ * Gets the current selectable zone af setting.
+ *
+ * @return one of SELECTABLE_ZONE_AF_XXX string constant. null if selectable zone af
+ * setting is not supported.
+ */
+ public String getSelectableZoneAf() {
+ return get(KEY_QC_SELECTABLE_ZONE_AF);
+ }
+
+ /** @hide
+ * Sets the current selectable zone af setting.
+ *
+ * @param value SELECTABLE_ZONE_AF_XXX string constants.
+ */
+ public void setSelectableZoneAf(String value) {
+ set(KEY_QC_SELECTABLE_ZONE_AF, value);
+ }
+
+ /** @hide
+ * Gets the current face detection setting.
+ *
+ * @return one of FACE_DETECTION_XXX string constant. null if face detection
+ * setting is not supported.
+ *
+ */
+ public String getFaceDetectionMode() {
+ return get(KEY_QC_FACE_DETECTION);
+ }
+
+ /** @hide
+ * Sets the auto scene detect. Other settings like Touch AF/AEC might be
+ * changed after setting face detection.
+ *
+ * @param value FACE_DETECTION_XXX string constants.
+ *
+ */
+ public void setFaceDetectionMode(String value) {
+ set(KEY_QC_FACE_DETECTION, value);
+ }
+
+ /** @hide
+ * Gets the current video rotation setting.
+ *
+ * @return one of VIDEO_QC_ROTATION_XXX string constant. null if video rotation
+ * setting is not supported.
+ */
+ public String getVideoRotation() {
+ return get(KEY_QC_VIDEO_ROTATION);
+ }
+
+ /** @hide
+ * Sets the current video rotation setting.
+ *
+ * @param value VIDEO_QC_ROTATION_XXX string constants.
+ */
+ public void setVideoRotation(String value) {
+ set(KEY_QC_VIDEO_ROTATION, value);
+ }
+ /** @hide
+ * Gets the supported video rotation modes.
+ *
+ * @return a List of VIDEO_QC_ROTATION_XXX string constant. null if this
+ * setting is not supported.
+ */
+ public List<String> getSupportedVideoRotationValues() {
+ String str = get(KEY_QC_VIDEO_ROTATION + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
+ // Splits a comma delimited string to an ArrayList of Coordinate.
+ // Return null if the passing string is null or the Coordinate is 0.
+ private ArrayList<Coordinate> splitCoordinate(String str) {
+ if (str == null) return null;
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(str);
+ ArrayList<Coordinate> coordinateList = new ArrayList<Coordinate>();
+ for (String s : splitter) {
+ Coordinate coordinate = strToCoordinate(s);
+ if (coordinate != null) coordinateList.add(coordinate);
+ }
+ if (coordinateList.size() == 0) return null;
+ return coordinateList;
+ }
+
+ // Parses a string (ex: "500x500") to Coordinate object.
+ // Return null if the passing string is null.
+ private Coordinate strToCoordinate(String str) {
+ if (str == null) return null;
+
+ int pos = str.indexOf('x');
+ if (pos != -1) {
+ String x = str.substring(0, pos);
+ String y = str.substring(pos + 1);
+ return new Coordinate(Integer.parseInt(x),
+ Integer.parseInt(y));
+ }
+ Log.e(TAG, "Invalid Coordinate parameter string=" + str);
+ return null;
+ }
+ /* ### QC ADD-ONS: END */
};
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 7abfabf..acfc415 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -144,6 +144,7 @@
@Override
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+ android.util.SeempLog.record_sensor_rate(381, sensor, delayUs);
if (listener == null || sensor == null) {
Log.e(TAG, "sensor or listener is null");
return false;
@@ -191,6 +192,7 @@
/** @hide */
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ android.util.SeempLog.record_sensor(382, sensor);
// Trigger Sensors should use the cancelTriggerSensor call.
if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
return;
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fb1ece2..bdec90d 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -510,6 +510,10 @@
@NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException;
+ /** @hide */
+ public abstract void setVendorStreamConfigMode(int index)
+ throws CameraAccessException;
+
/**
* <p>Create a new camera capture session by providing the target output set of Surfaces and
* its corresponding surface configuration to the camera device.</p>
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index fc90096..4fe533b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -22,6 +22,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
@@ -39,6 +40,8 @@
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Size;
@@ -1014,8 +1017,22 @@
}
private String[] extractCameraIdListLocked() {
String[] cameraIds = null;
+ boolean exposeAuxCamera = false;
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ exposeAuxCamera = true;
+ break;
+ }
+ }
+ }
int idCount = 0;
for (int i = 0; i < mDeviceStatus.size(); i++) {
+ if(!exposeAuxCamera && (i == 2)) break;
int status = mDeviceStatus.valueAt(i);
if (status == ICameraServiceListener.STATUS_NOT_PRESENT
|| status == ICameraServiceListener.STATUS_ENUMERATING) continue;
@@ -1024,6 +1041,7 @@
cameraIds = new String[idCount];
idCount = 0;
for (int i = 0; i < mDeviceStatus.size(); i++) {
+ if(!exposeAuxCamera && (i == 2)) break;
int status = mDeviceStatus.valueAt(i);
if (status == ICameraServiceListener.STATUS_NOT_PRESENT
|| status == ICameraServiceListener.STATUS_ENUMERATING) continue;
@@ -1156,6 +1174,26 @@
throw new IllegalArgumentException("cameraId was null");
}
+ /* Force to expose only two cameras
+ * if the package name does not falls in this bucket
+ */
+ boolean exposeAuxCamera = false;
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ exposeAuxCamera = true;
+ break;
+ }
+ }
+ }
+ if (exposeAuxCamera == false && (Integer.parseInt(cameraId) >= 2)) {
+ throw new IllegalArgumentException("invalid cameraId");
+ }
+
ICameraService cameraService = getCameraService();
if (cameraService == null) {
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -1305,6 +1343,30 @@
}
private void onStatusChangedLocked(int status, String id) {
+ /* Force to ignore the last mono/aux camera status update
+ * if the package name does not falls in this bucket
+ */
+ boolean exposeMonoCamera = false;
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ exposeMonoCamera = true;
+ break;
+ }
+ }
+ }
+
+ if (exposeMonoCamera == false) {
+ if (Integer.parseInt(id) >= 2) {
+ Log.w(TAG, "[soar.cts] ignore the status update of camera: " + id);
+ return;
+ }
+ }
+
if (DEBUG) {
Log.v(TAG,
String.format("Camera id %s has status changed to 0x%x", id, status));
@@ -1380,6 +1442,31 @@
String.format("Camera id %s has torch status changed to 0x%x", id, status));
}
+ /* Force to ignore the aux or composite camera torch status update
+ * if the package name does not falls in this bucket
+ */
+ boolean exposeMonoCamera = false;
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ exposeMonoCamera = true;
+ break;
+ }
+ }
+ }
+
+ if (exposeMonoCamera == false) {
+ if (Integer.parseInt(id) >= 2) {
+ Log.w(TAG, "ignore the torch status update of camera: " + id);
+ return;
+ }
+ }
+
+
if (!validTorchStatus(status)) {
Log.e(TAG, String.format("Ignoring invalid device %s torch status 0x%x", id,
status));
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index a4640c1..eee5f7f 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -206,7 +206,8 @@
} else if (request.isReprocess() && !isReprocessable()) {
throw new IllegalArgumentException("this capture session cannot handle reprocess " +
"requests");
- } else if (request.isReprocess() && request.getReprocessableSessionId() != mId) {
+ } else if (!mDeviceImpl.isPrivilegedApp() &&
+ request.isReprocess() && request.getReprocessableSessionId() != mId) {
throw new IllegalArgumentException("capture request was created for another session");
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index eb33137..beb6749 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -23,10 +23,12 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
import android.os.ConditionVariable;
import android.util.Range;
+import android.util.Size;
import android.view.Surface;
import java.util.ArrayList;
@@ -86,10 +88,7 @@
mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config);
- // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
- // the preview frame rate, should use maxBatch size for that high speed stream
- // configuration. We choose the former for now.
- int requestListSize = fpsRange.getUpper() / 30;
+ int requestListSize = getHighSpeedRequestListSize(fpsRange, outputSurfaces);
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
// Prepare the Request builders: need carry over the request controls.
@@ -168,6 +167,34 @@
return true;
}
+ private int getHighSpeedRequestListSize(Range<Integer> fpsRange, Collection<Surface> surfaces) {
+ int requestListSize = 0;
+
+ for (Surface surface : surfaces) {
+
+ if (SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
+ HighSpeedVideoConfiguration[] highSpeedVideoConfigurations =
+ mCharacteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+
+ // Get the batchsize for matching FPS & video size
+ for (HighSpeedVideoConfiguration config : highSpeedVideoConfigurations) {
+ if (config.getSize().equals(surfaceSize) && config.getFpsRange().equals(fpsRange)) {
+ requestListSize = config.getBatchSizeMax();
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (requestListSize == 0) {
+ // If cant' find the matching batch size, limit the preview to 30fps.
+ requestListSize = fpsRange.getUpper() / 30;
+ }
+ return requestListSize;
+ }
+
@Override
public CameraDevice getDevice() {
return mSessionImpl.getDevice();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index bcbc337..b15c5fe 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -16,10 +16,13 @@
package android.hardware.camera2.impl;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import android.annotation.NonNull;
import android.hardware.ICameraService;
+import android.app.ActivityThread;
+import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -43,6 +46,8 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Range;
import android.util.Size;
@@ -74,7 +79,7 @@
private final boolean DEBUG = false;
private static final int REQUEST_ID_NONE = -1;
-
+ private int customOpMode = 0;
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
private ICameraDeviceUserWrapper mRemoteDevice;
@@ -126,6 +131,7 @@
private int mNextSessionId = 0;
private final int mAppTargetSdkVersion;
+ private boolean mIsPrivilegedApp = false;
// Runnables for all state transitions, except error, which needs the
// error code argument
@@ -268,6 +274,7 @@
} else {
mTotalPartialCount = partialCount;
}
+ mIsPrivilegedApp = checkPrivilegedAppList();
}
public CameraDeviceCallbacks getCallbacks() {
@@ -356,6 +363,10 @@
}
}
+ public void setVendorStreamConfigMode(int fpsrange) {
+ customOpMode = fpsrange;
+ }
+
@Override
public String getId() {
return mCameraId;
@@ -469,6 +480,7 @@
mConfiguredOutputs.put(streamId, outConfig);
}
}
+ operatingMode = (operatingMode | (customOpMode << 16));
if (sessionParams != null) {
mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
@@ -1219,11 +1231,41 @@
}
}
+ private boolean checkPrivilegedAppList() {
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("persist.vendor.camera.privapp.list");
+
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isPrivilegedApp() {
+ return mIsPrivilegedApp;
+ }
+
private void checkInputConfiguration(InputConfiguration inputConfig) {
if (inputConfig != null) {
StreamConfigurationMap configMap = mCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ /*
+ * don't check input format and size,
+ * if the package name is in the white list
+ */
+ if (isPrivilegedApp()) {
+ Log.w(TAG, "ignore input format/size check for white listed app");
+ return;
+ }
+
int[] inputFormats = configMap.getInputFormats();
boolean validFormat = false;
for (int format : inputFormats) {
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index d3c4505..9eb8d32 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -30,6 +30,11 @@
import java.util.Iterator;
import java.util.List;
+import android.app.ActivityThread;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+
+
/**
* Various Surface utilities.
*/
@@ -157,7 +162,13 @@
+ " the size must be 1 or 2");
}
+ if (isPrivilegedApp()) {
+ //skip checks for privileged apps
+ return;
+ }
+
List<Size> highSpeedSizes = null;
+
if (fpsRange == null) {
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
} else {
@@ -209,4 +220,20 @@
}
}
+ private static boolean isPrivilegedApp() {
+ String packageName = ActivityThread.currentOpPackageName();
+ String packageList = SystemProperties.get("persist.camera.privapp.list");
+
+ if (packageList.length() > 0) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(packageList);
+ for (String str : splitter) {
+ if (packageName.equals(str)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cfa3934..274c35f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -481,6 +481,13 @@
public static final int TETHERING_WIFI_P2P = 3;
/**
+ * WIGIG tethering type. Use a separate type to prevent
+ * conflicts with TETHERING_WIFI
+ * @hide
+ */
+ public static final int TETHERING_WIGIG = 4;
+
+ /**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
* @hide
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 6c7aa13..c883e06 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -712,6 +712,7 @@
entry.operations += operations[i];
}
}
+
return entry;
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b2cfdd..c758031 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,6 +34,7 @@
import android.nfc.ITagRemovedCallback;
import android.nfc.INfcDta;
import android.os.Bundle;
+import android.os.IBinder;
/**
* @hide
@@ -42,6 +46,8 @@
INfcFCardEmulation getNfcFCardEmulationInterface();
INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
INfcDta getNfcDtaInterface(in String pkg);
+ IBinder getNfcAdapterVendorInterface(in String vendor);
+
int getState();
boolean disable(boolean saveState);
boolean enable();
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 77b5552..f75f79e 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,7 +41,7 @@
*
* @hide
*/
-public final class AidGroup implements Parcelable {
+public class AidGroup implements Parcelable {
/**
* The maximum number of AIDs that can be present in any one group.
*/
@@ -47,11 +50,11 @@
static final String TAG = "AidGroup";
@UnsupportedAppUsage
- final List<String> aids;
+ protected List<String> aids;
@UnsupportedAppUsage
- final String category;
+ protected String category;
@UnsupportedAppUsage
- final String description;
+ protected String description;
/**
* Creates a new AidGroup object.
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index d9000e4..f876c47 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,24 +50,24 @@
/**
* @hide
*/
-public final class ApduServiceInfo implements Parcelable {
+public class ApduServiceInfo implements Parcelable {
static final String TAG = "ApduServiceInfo";
/**
* The service that implements this
*/
@UnsupportedAppUsage
- final ResolveInfo mService;
+ protected ResolveInfo mService;
/**
* Description of the service
*/
- final String mDescription;
+ protected String mDescription;
/**
* Whether this service represents AIDs running on the host CPU
*/
- final boolean mOnHost;
+ protected boolean mOnHost;
/**
* Offhost reader name.
@@ -82,33 +85,33 @@
* Mapping from category to static AID group
*/
@UnsupportedAppUsage
- final HashMap<String, AidGroup> mStaticAidGroups;
+ protected HashMap<String, AidGroup> mStaticAidGroups;
/**
* Mapping from category to dynamic AID group
*/
@UnsupportedAppUsage
- final HashMap<String, AidGroup> mDynamicAidGroups;
+ protected HashMap<String, AidGroup> mDynamicAidGroups;
/**
* Whether this service should only be started when the device is unlocked.
*/
- final boolean mRequiresDeviceUnlock;
+ protected boolean mRequiresDeviceUnlock;
/**
* The id of the service banner specified in XML.
*/
- final int mBannerResourceId;
+ protected int mBannerResourceId;
/**
* The uid of the package the service belongs to
*/
- final int mUid;
+ protected int mUid;
/**
* Settings Activity for this service
*/
- final String mSettingsActivityName;
+ protected String mSettingsActivityName;
/**
* @hide
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index 080e058..9cae043 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2018 NXP Semiconductors
+ * The original Work has been changed by NXP Semiconductors.
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -173,6 +175,10 @@
mType = TYPE_CLASSIC;
mSize = SIZE_4K;
break;
+ case 0x19:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_2K;
+ break;
case 0x28:
mType = TYPE_CLASSIC;
mSize = SIZE_1K;
diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index 88730f9..819e9e3 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2018 NXP Semiconductors
+ * The original Work has been changed by NXP Semiconductors.
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -66,8 +68,15 @@
/** @hide */
public NfcA(Tag tag) throws RemoteException {
super(tag, TagTechnology.NFC_A);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_A);
- mSak = extras.getShort(EXTRA_SAK);
+ Bundle extras;
+ mSak = 0;
+ if(tag.hasTech(TagTechnology.MIFARE_CLASSIC))
+ {
+ extras = tag.getTechExtras(TagTechnology.MIFARE_CLASSIC);
+ mSak = extras.getShort(EXTRA_SAK);
+ }
+ extras = tag.getTechExtras(TagTechnology.NFC_A);
+ mSak |= extras.getShort(EXTRA_SAK);
mAtqa = extras.getByteArray(EXTRA_ATQA);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 43b9c67..6b2000e 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -819,6 +819,30 @@
throws IllegalArgumentException, SecurityException;
/**
+ * Sets the scheduling group for processes in the same cgroup.procs of uid and pid
+ * @hide
+ * @param uid The user identifier of the process to change.
+ * @param pid The identifier of the process to change.
+ * @param group The target group for this process from THREAD_GROUP_*.
+ *
+ * @throws IllegalArgumentException Throws IllegalArgumentException if
+ * <var>tid</var> does not exist.
+ * @throws SecurityException Throws SecurityException if your process does
+ * not have permission to modify the given thread, or to use the given
+ * priority.
+ *
+ * group == THREAD_GROUP_DEFAULT means to move all non-background priority
+ * threads to the foreground scheduling group, but to leave background
+ * priority threads alone. group == THREAD_GROUP_BG_NONINTERACTIVE moves all
+ * threads, regardless of priority, to the background scheduling group.
+ * group == THREAD_GROUP_FOREGROUND is not allowed.
+ *
+ * Always sets cpusets.
+ */
+ public static final native void setCgroupProcsProcessGroup(int uid, int pid, int group)
+ throws IllegalArgumentException, SecurityException;
+
+ /**
* Return the scheduling group of requested process.
*
* @hide
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index b797324..19d1ce1 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
public static final int FLAG_SD = 1 << 2;
public static final int FLAG_USB = 1 << 3;
+ public static final int FLAG_EMMC = 1 << 4;
+ public static final int FLAG_UFS_CARD = 1 << 5;
public final String id;
@UnsupportedAppUsage
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 92fecad..bbc936d 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -193,4 +193,5 @@
void startCheckpoint(int numTries) = 85;
boolean needsCheckpoint() = 86;
void abortChanges(in String message, boolean retry) = 87;
+ void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 30021b4..7bb149d 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -246,6 +246,7 @@
*/
public static final Cursor getAllBookmarks(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(32);
return new MatrixCursor(new String[]{Bookmarks.URL}, 0);
}
@@ -258,6 +259,7 @@
*/
public static final Cursor getAllVisitedUrls(ContentResolver cr) throws
IllegalStateException {
+ android.util.SeempLog.record(33);
return new MatrixCursor(new String[]{Combined.URL}, 0);
}
@@ -266,6 +268,7 @@
}
private static final Cursor getVisitedLike(ContentResolver cr, String url) {
+ android.util.SeempLog.record(34);
boolean secure = false;
String compareString = url;
if (compareString.startsWith("http://")) {
@@ -327,6 +330,7 @@
@Deprecated
@UnsupportedAppUsage
public static final String[] getVisitedHistory(ContentResolver cr) {
+ android.util.SeempLog.record(35);
return new String[0];
}
@@ -362,6 +366,7 @@
* @removed
*/
public static final void clearHistory(ContentResolver cr) {
+ android.util.SeempLog.record(37);
}
@@ -423,6 +428,7 @@
*/
public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) {
+ android.util.SeempLog.record(36);
// Do nothing: this is no longer used.
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d862d602..293e69d 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -983,6 +983,7 @@
* @return A Cursor containing all attendees for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] attArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, ATTENDEES_WHERE, attArgs /* selection args */,
null /* sort order */);
@@ -1915,6 +1916,7 @@
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -1944,6 +1946,7 @@
*/
public static final Cursor query(ContentResolver cr, String[] projection,
long begin, long end, String searchQuery) {
+ android.util.SeempLog.record(54);
Uri.Builder builder = CONTENT_SEARCH_URI.buildUpon();
ContentUris.appendId(builder, begin);
ContentUris.appendId(builder, end);
@@ -2255,6 +2258,7 @@
*/
public static final Cursor query(ContentResolver cr, int startDay, int numDays,
String[] projection) {
+ android.util.SeempLog.record(54);
if (numDays < 1) {
return null;
}
@@ -2338,6 +2342,7 @@
* @return A Cursor containing all reminders for the event
*/
public static final Cursor query(ContentResolver cr, long eventId, String[] projection) {
+ android.util.SeempLog.record(54);
String[] remArgs = {Long.toString(eventId)};
return cr.query(CONTENT_URI, projection, REMINDERS_WHERE, remArgs /*selection args*/,
null /* sort order */);
@@ -2488,6 +2493,7 @@
*/
public static final Uri insert(ContentResolver cr, long eventId,
long begin, long end, long alarmTime, int minutes) {
+ android.util.SeempLog.record(51);
ContentValues values = new ContentValues();
values.put(CalendarAlerts.EVENT_ID, eventId);
values.put(CalendarAlerts.BEGIN, begin);
@@ -2516,6 +2522,7 @@
*/
@UnsupportedAppUsage
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
+ android.util.SeempLog.record(53);
String selection = ALARM_TIME + ">=" + millis;
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
@@ -2640,6 +2647,7 @@
*/
public static final boolean alarmExists(ContentResolver cr, long eventId,
long begin, long alarmTime) {
+ android.util.SeempLog.record(52);
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index af3a16c..8290eee 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1625,6 +1625,7 @@
* {@link #CONTENT_LOOKUP_URI} to attempt refreshing.
*/
public static Uri getLookupUri(ContentResolver resolver, Uri contactUri) {
+ android.util.SeempLog.record(86);
final Cursor c = resolver.query(contactUri, new String[] {
Contacts.LOOKUP_KEY, Contacts._ID
}, null, null, null);
@@ -1652,6 +1653,7 @@
* provided parameters.
*/
public static Uri getLookupUri(long contactId, String lookupKey) {
+ android.util.SeempLog.record(86);
if (TextUtils.isEmpty(lookupKey)) {
return null;
}
@@ -1665,6 +1667,7 @@
* Returns null if the contact cannot be found.
*/
public static Uri lookupContact(ContentResolver resolver, Uri lookupUri) {
+ android.util.SeempLog.record(87);
if (lookupUri == null) {
return null;
}
@@ -2157,6 +2160,7 @@
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
boolean preferHighres) {
+ android.util.SeempLog.record(88);
if (preferHighres) {
final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
Contacts.Photo.DISPLAY_PHOTO);
@@ -2205,6 +2209,7 @@
* of the thumbnail the high-res picture is preferred
*/
public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ android.util.SeempLog.record(88);
return openContactPhotoInputStream(cr, contactUri, false);
}
}
@@ -2881,6 +2886,7 @@
* entry of the given {@link RawContacts} entry.
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri rawContactUri) {
+ android.util.SeempLog.record(89);
// TODO: use a lighter query by joining rawcontacts with contacts in provider
final Uri dataUri = Uri.withAppendedPath(rawContactUri, Data.CONTENT_DIRECTORY);
final Cursor cursor = resolver.query(dataUri, new String[] {
@@ -4888,6 +4894,7 @@
* </p>
*/
public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
+ android.util.SeempLog.record(89);
final Cursor cursor = resolver.query(dataUri, new String[] {
RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
}, null, null, null);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cff99f3..00ac378 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2795,6 +2795,7 @@
@UnsupportedAppUsage
public static String getStringForUser(ContentResolver resolver, String name,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempGetApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, returning read-only value.");
@@ -2823,6 +2824,7 @@
@UnsupportedAppUsage
public static boolean putStringForUser(ContentResolver resolver, String name, String value,
int userHandle) {
+ android.util.SeempLog.record(android.util.SeempLog.getSeempPutApiIdFromValue(name));
if (MOVED_TO_SECURE.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+ " to android.provider.Settings.Secure, value is unchanged.");
@@ -4845,6 +4847,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.NITZ_UPDATE_SPACING);
MOVED_TO_GLOBAL.add(Settings.Global.NTP_SERVER);
MOVED_TO_GLOBAL.add(Settings.Global.NTP_TIMEOUT);
+ MOVED_TO_GLOBAL.add(Settings.Global.NTP_SERVER_2);
MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT);
MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
@@ -4872,6 +4875,7 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COVERAGE_EXTEND_FEATURE_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
@@ -5854,6 +5858,13 @@
public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2;
/**
+ * Setting to configure Wifi disconnect delay duration in seconds.
+ * @hide
+ **/
+ public static final String WIFI_DISCONNECT_DELAY_DURATION =
+ "wifi_disconnect_delay_duration";
+
+ /**
* Location mode is off.
*/
public static final int LOCATION_MODE_OFF = 0;
@@ -9106,6 +9117,8 @@
public static final String NTP_SERVER = "ntp_server";
/** Timeout in milliseconds to wait for NTP server. {@hide} */
public static final String NTP_TIMEOUT = "ntp_timeout";
+ /** Secondary NTP server. {@hide} */
+ public static final String NTP_SERVER_2 = "ntp_server_2";
/** {@hide} */
public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
@@ -9841,6 +9854,14 @@
public static final String WIFI_VERBOSE_LOGGING_ENABLED =
"wifi_verbose_logging_enabled";
+ /**
+ * Setting to enable Wi-Fi coverage extend feature; disabled by default, and setting to 1
+ * will enable it.
+ * @hide
+ */
+ public static final String WIFI_COVERAGE_EXTEND_FEATURE_ENABLED =
+ "wifi_coverage_extend_feature_enabled";
+
/**
* Setting to enable connected MAC randomization in Wi-Fi; disabled by default, and
* setting to 1 will enable it. In the future, additional values may be supported.
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index af5bf74..56b9be8 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -55,12 +55,13 @@
private @Nullable String mImsi;
private @Nullable String mGid1;
private @Nullable String mGid2;
+ private @Nullable String mIccid;
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSpecificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
public CarrierIdentifier(String mcc, String mnc, @Nullable String spn, @Nullable String imsi,
@Nullable String gid1, @Nullable String gid2) {
- this(mcc, mnc, spn, imsi, gid1, gid2, TelephonyManager.UNKNOWN_CARRIER_ID,
+ this(mcc, mnc, spn, imsi, gid1, gid2, null, TelephonyManager.UNKNOWN_CARRIER_ID,
TelephonyManager.UNKNOWN_CARRIER_ID);
}
@@ -79,16 +80,31 @@
public CarrierIdentifier(@NonNull String mcc, @NonNull String mnc, @Nullable String spn,
@Nullable String imsi, @Nullable String gid1, @Nullable String gid2,
int carrierid, int specificCarrierId) {
+ this(mcc, mnc, spn, imsi, gid1, gid2, null, carrierid, specificCarrierId);
+ }
+
+ /** @hide */
+ public CarrierIdentifier(String mcc, String mnc, @Nullable String spn,
+ @Nullable String imsi, @Nullable String gid1, @Nullable String gid2,
+ @Nullable String iccid, int carrierid, int specificCarrierId) {
mMcc = mcc;
mMnc = mnc;
mSpn = spn;
mImsi = imsi;
mGid1 = gid1;
mGid2 = gid2;
+ mIccid = iccid;
mCarrierId = carrierid;
mSpecificCarrierId = specificCarrierId;
}
+ /** @hide */
+ public CarrierIdentifier(String mcc, String mnc, @Nullable String spn, @Nullable String imsi,
+ @Nullable String gid1, @Nullable String gid2I, @Nullable String iccid) {
+ this(mcc, mnc, spn, imsi, gid1, gid2I);
+ mIccid = iccid;
+ }
+
/**
* Creates a carrier identifier instance.
*
@@ -113,6 +129,7 @@
mGid2 = gid2;
mSpn = null;
mImsi = null;
+ mIccid = null;
}
/** @hide */
@@ -154,6 +171,13 @@
return mGid2;
}
+ /** Get the ICCID.
+ * @hide */
+ @Nullable
+ public String getIccid() {
+ return mIccid;
+ }
+
/**
* Returns the carrier id.
* @see TelephonyManager#getSimCarrierId()
@@ -192,13 +216,14 @@
&& Objects.equals(mImsi, that.mImsi)
&& Objects.equals(mGid1, that.mGid1)
&& Objects.equals(mGid2, that.mGid2)
+ && Objects.equals(mIccid, that.mIccid)
&& Objects.equals(mCarrierId, that.mCarrierId)
&& Objects.equals(mSpecificCarrierId, that.mSpecificCarrierId);
}
@Override
public int hashCode(){
- return Objects.hash(mMcc, mMnc, mSpn, mImsi, mGid1, mGid2, mCarrierId, mSpecificCarrierId);
+ return Objects.hash(mMcc, mMnc, mSpn, mImsi, mGid1, mGid2, mIccid, mCarrierId, mSpecificCarrierId);
}
@Override
@@ -214,6 +239,7 @@
out.writeString(mImsi);
out.writeString(mGid1);
out.writeString(mGid2);
+ out.writeString(mIccid);
out.writeInt(mCarrierId);
out.writeInt(mSpecificCarrierId);
}
@@ -227,6 +253,7 @@
+ ",imsi=" + Rlog.pii(false, mImsi)
+ ",gid1=" + mGid1
+ ",gid2=" + mGid2
+ + ",iccid=" + mIccid
+ ",carrierid=" + mCarrierId
+ ",specificCarrierId=" + mSpecificCarrierId
+ "}";
@@ -240,6 +267,7 @@
mImsi = in.readString();
mGid1 = in.readString();
mGid2 = in.readString();
+ mIccid = in.readString();
mCarrierId = in.readInt();
mSpecificCarrierId = in.readInt();
}
@@ -251,5 +279,6 @@
int IMSI_PREFIX = 2;
int GID1 = 3;
int GID2 = 4;
+ int ICCID = 5;
}
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e784ad3..2e920bc 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1441,7 +1441,7 @@
return;
}
case MSG_UPDATE_SURFACE:
- mEngine.updateSurface(true, false, false);
+ mEngine.updateSurface(true, false, true/*false*/);
break;
case MSG_VISIBILITY_CHANGED:
if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 88e2ede..3eb24e4 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -260,6 +260,7 @@
* not set explicitly, default values will be used by the recognizer.
*/
public void startListening(final Intent recognizerIntent) {
+ android.util.SeempLog.record(72);
if (recognizerIntent == null) {
throw new IllegalArgumentException("intent must not be null");
}
diff --git a/core/java/android/util/BoostFramework.java b/core/java/android/util/BoostFramework.java
new file mode 100644
index 0000000..f839b42
--- /dev/null
+++ b/core/java/android/util/BoostFramework.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.util;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/** @hide */
+public class BoostFramework {
+
+ private static final String TAG = "BoostFramework";
+ private static final String PERFORMANCE_JAR = "/system/framework/QPerformance.jar";
+ private static final String PERFORMANCE_CLASS = "com.qualcomm.qti.Performance";
+
+ private static final String UXPERFORMANCE_JAR = "/system/framework/UxPerformance.jar";
+ private static final String UXPERFORMANCE_CLASS = "com.qualcomm.qti.UxPerformance";
+
+/** @hide */
+ private static boolean sIsLoaded = false;
+ private static Class<?> sPerfClass = null;
+ private static Method sAcquireFunc = null;
+ private static Method sPerfHintFunc = null;
+ private static Method sReleaseFunc = null;
+ private static Method sReleaseHandlerFunc = null;
+ private static Method sFeedbackFunc = null;
+ private static Method sPerfGetPropFunc = null;
+
+ private static Method sIOPStart = null;
+ private static Method sIOPStop = null;
+ private static Method sUXEngineEvents = null;
+ private static Method sUXEngineTrigger = null;
+
+ private static boolean sUxIsLoaded = false;
+ private static Class<?> sUxPerfClass = null;
+ private static Method sUxIOPStart = null;
+
+/** @hide */
+ private Object mPerf = null;
+ private Object mUxPerf = null;
+
+ //perf hints
+ public static final int VENDOR_HINT_SCROLL_BOOST = 0x00001080;
+ public static final int VENDOR_HINT_FIRST_LAUNCH_BOOST = 0x00001081;
+ public static final int VENDOR_HINT_SUBSEQ_LAUNCH_BOOST = 0x00001082;
+ public static final int VENDOR_HINT_ANIM_BOOST = 0x00001083;
+ public static final int VENDOR_HINT_ACTIVITY_BOOST = 0x00001084;
+ public static final int VENDOR_HINT_TOUCH_BOOST = 0x00001085;
+ public static final int VENDOR_HINT_MTP_BOOST = 0x00001086;
+ public static final int VENDOR_HINT_DRAG_BOOST = 0x00001087;
+ public static final int VENDOR_HINT_PACKAGE_INSTALL_BOOST = 0x00001088;
+ public static final int VENDOR_HINT_ROTATION_LATENCY_BOOST = 0x00001089;
+ public static final int VENDOR_HINT_ROTATION_ANIM_BOOST = 0x00001090;
+ public static final int VENDOR_HINT_PERFORMANCE_MODE = 0x00001091;
+ public static final int VENDOR_HINT_APP_UPDATE = 0x00001092;
+ public static final int VENDOR_HINT_KILL = 0x00001093;
+ //perf events
+ public static final int VENDOR_HINT_FIRST_DRAW = 0x00001042;
+ public static final int VENDOR_HINT_TAP_EVENT = 0x00001043;
+ //feedback hints
+ public static final int VENDOR_FEEDBACK_WORKLOAD_TYPE = 0x00001601;
+ public static final int VENDOR_FEEDBACK_LAUNCH_END_POINT = 0x00001602;
+
+ //UXE Events and Triggers
+ public static final int UXE_TRIGGER = 1;
+ public static final int UXE_EVENT_BINDAPP = 2;
+ public static final int UXE_EVENT_DISPLAYED_ACT = 3;
+ public static final int UXE_EVENT_KILL = 4;
+ public static final int UXE_EVENT_GAME = 5;
+ public static final int UXE_EVENT_SUB_LAUNCH = 6;
+ public static final int UXE_EVENT_PKG_UNINSTALL = 7;
+ public static final int UXE_EVENT_PKG_INSTALL = 8;
+
+ public class Scroll {
+ public static final int VERTICAL = 1;
+ public static final int HORIZONTAL = 2;
+ public static final int PANEL_VIEW = 3;
+ public static final int PREFILING = 4;
+ };
+
+ public class Launch {
+ public static final int BOOST_V1 = 1;
+ public static final int BOOST_V2 = 2;
+ public static final int BOOST_V3 = 3;
+ public static final int BOOST_GAME = 4;
+ public static final int RESERVED_1 = 5;
+ public static final int RESERVED_2 = 6;
+ public static final int TYPE_SERVICE_START = 100;
+ public static final int TYPE_START_PROC = 101;
+ public static final int TYPE_START_APP_FROM_BG = 102;
+ };
+
+ public class Draw {
+ public static final int EVENT_TYPE_V1 = 1;
+ };
+
+ public class WorkloadType {
+ public static final int NOT_KNOWN = 0;
+ public static final int APP = 1;
+ public static final int GAME = 2;
+ public static final int BROWSER = 3;
+ public static final int PREPROAPP = 4;
+ };
+
+/** @hide */
+ public BoostFramework() {
+ initFunctions();
+
+ try {
+ if (sPerfClass != null) {
+ mPerf = sPerfClass.newInstance();
+ }
+ if (sUxPerfClass != null) {
+ mUxPerf = sUxPerfClass.newInstance();
+ }
+ }
+ catch(Exception e) {
+ Log.e(TAG,"BoostFramework() : Exception_2 = " + e);
+ }
+ }
+
+/** @hide */
+ public BoostFramework(Context context) {
+ initFunctions();
+
+ try {
+ if (sPerfClass != null) {
+ Constructor cons = sPerfClass.getConstructor(Context.class);
+ if (cons != null)
+ mPerf = cons.newInstance(context);
+ }
+ if (sUxPerfClass != null) {
+ mUxPerf = sUxPerfClass.newInstance();
+ }
+ }
+ catch(Exception e) {
+ Log.e(TAG,"BoostFramework() : Exception_3 = " + e);
+ }
+ }
+
+/** @hide */
+ public BoostFramework(boolean isUntrustedDomain) {
+ initFunctions();
+
+ try {
+ if (sPerfClass != null) {
+ Constructor cons = sPerfClass.getConstructor(boolean.class);
+ if (cons != null)
+ mPerf = cons.newInstance(isUntrustedDomain);
+ }
+ if (sUxPerfClass != null) {
+ mUxPerf = sUxPerfClass.newInstance();
+ }
+ }
+ catch(Exception e) {
+ Log.e(TAG,"BoostFramework() : Exception_5 = " + e);
+ }
+ }
+
+ private void initFunctions () {
+ synchronized(BoostFramework.class) {
+ if (sIsLoaded == false) {
+ try {
+ sPerfClass = Class.forName(PERFORMANCE_CLASS);
+
+ Class[] argClasses = new Class[] {int.class, int[].class};
+ sAcquireFunc = sPerfClass.getMethod("perfLockAcquire", argClasses);
+
+ argClasses = new Class[] {int.class, String.class, int.class, int.class};
+ sPerfHintFunc = sPerfClass.getMethod("perfHint", argClasses);
+
+ argClasses = new Class[] {};
+ sReleaseFunc = sPerfClass.getMethod("perfLockRelease", argClasses);
+
+ argClasses = new Class[] {int.class};
+ sReleaseHandlerFunc = sPerfClass.getDeclaredMethod("perfLockReleaseHandler", argClasses);
+
+ argClasses = new Class[] {int.class, String.class};
+ sFeedbackFunc = sPerfClass.getMethod("perfGetFeedback", argClasses);
+
+ argClasses = new Class[] {int.class, String.class, String.class};
+ sIOPStart = sPerfClass.getDeclaredMethod("perfIOPrefetchStart", argClasses);
+
+ argClasses = new Class[] {};
+ sIOPStop = sPerfClass.getDeclaredMethod("perfIOPrefetchStop", argClasses);
+
+ argClasses = new Class[] {String.class, String.class};
+ sPerfGetPropFunc = sPerfClass.getMethod("perfGetProp", argClasses);
+
+ try {
+ argClasses = new Class[] {int.class, int.class, String.class, int.class, String.class};
+ sUXEngineEvents = sPerfClass.getDeclaredMethod("perfUXEngine_events",
+ argClasses);
+
+ argClasses = new Class[] {int.class};
+ sUXEngineTrigger = sPerfClass.getDeclaredMethod("perfUXEngine_trigger",
+ argClasses);
+ } catch (Exception e) {
+ Log.i(TAG, "BoostFramework() : Exception_4 = PreferredApps not supported");
+ }
+
+ sIsLoaded = true;
+ }
+ catch(Exception e) {
+ Log.e(TAG,"BoostFramework() : Exception_1 = " + e);
+ }
+ // Load UXE Class now Adding new try/catch block to avoid
+ // any interference with Qperformance
+ try {
+ sUxPerfClass = Class.forName(UXPERFORMANCE_CLASS);
+
+ Class[] argUxClasses = new Class[] {int.class, String.class, String.class};
+ sUxIOPStart = sUxPerfClass.getDeclaredMethod("perfIOPrefetchStart", argUxClasses);
+
+ sUxIsLoaded = true;
+ }
+ catch(Exception e) {
+ Log.e(TAG,"BoostFramework() Ux Perf: Exception = " + e);
+ }
+ }
+ }
+ }
+
+/** @hide */
+ public int perfLockAcquire(int duration, int... list) {
+ int ret = -1;
+ try {
+ if (sAcquireFunc != null) {
+ Object retVal = sAcquireFunc.invoke(mPerf, duration, list);
+ ret = (int)retVal;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfLockRelease() {
+ int ret = -1;
+ try {
+ if (sReleaseFunc != null) {
+ Object retVal = sReleaseFunc.invoke(mPerf);
+ ret = (int)retVal;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfLockReleaseHandler(int handle) {
+ int ret = -1;
+ try {
+ if (sReleaseHandlerFunc != null) {
+ Object retVal = sReleaseHandlerFunc.invoke(mPerf, handle);
+ ret = (int)retVal;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfHint(int hint, String userDataStr) {
+ return perfHint(hint, userDataStr, -1, -1);
+ }
+
+/** @hide */
+ public int perfHint(int hint, String userDataStr, int userData) {
+ return perfHint(hint, userDataStr, userData, -1);
+ }
+
+/** @hide */
+ public int perfHint(int hint, String userDataStr, int userData1, int userData2) {
+ int ret = -1;
+ try {
+ if (sPerfHintFunc != null) {
+ Object retVal = sPerfHintFunc.invoke(mPerf, hint, userDataStr, userData1, userData2);
+ ret = (int)retVal;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfGetFeedback(int req, String userDataStr) {
+ int ret = -1;
+ try {
+ if (sFeedbackFunc != null) {
+ Object retVal = sFeedbackFunc.invoke(mPerf, req, userDataStr);
+ ret = (int)retVal;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfIOPrefetchStart(int pid, String pkgName, String codePath) {
+ int ret = -1;
+ try {
+ Object retVal = sIOPStart.invoke(mPerf, pid, pkgName, codePath);
+ ret = (int) retVal;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ try {
+ Object retVal = sUxIOPStart.invoke(mUxPerf, pid, pkgName, codePath);
+ ret = (int) retVal;
+ } catch (Exception e) {
+ Log.e(TAG, "Ux Perf Exception " + e);
+ }
+
+ return ret;
+ }
+
+/** @hide */
+ public int perfIOPrefetchStop() {
+ int ret = -1;
+ try {
+ Object retVal = sIOPStop.invoke(mPerf);
+ ret = (int) retVal;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ return ret;
+ }
+
+/** @hide */
+ public int perfUXEngine_events(int opcode, int pid, String pkgName, int lat) {
+ return perfUXEngine_events(opcode, pid, pkgName, lat, null);
+ }
+
+/** @hide */
+ public int perfUXEngine_events(int opcode, int pid, String pkgName, int lat, String codePath) {
+ int ret = -1;
+ try {
+ if (sUXEngineEvents == null) {
+ return ret;
+ }
+
+ Object retVal = sUXEngineEvents.invoke(mPerf, opcode, pid, pkgName, lat,codePath);
+ ret = (int) retVal;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ return ret;
+ }
+
+
+/** @hide */
+ public String perfUXEngine_trigger(int opcode) {
+ String ret = null;
+ try {
+ if (sUXEngineTrigger == null) {
+ return ret;
+ }
+ Object retVal = sUXEngineTrigger.invoke(mPerf, opcode);
+ ret = (String) retVal;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ return ret;
+ }
+
+
+ public String perfGetProp(String prop_name, String def_val) {
+ String ret = "";
+ try {
+ if (sPerfGetPropFunc != null) {
+ Object retVal = sPerfGetPropFunc.invoke(mPerf, prop_name, def_val);
+ ret = (String)retVal;
+ }else {
+ ret = def_val;
+ }
+ } catch(Exception e) {
+ Log.e(TAG,"Exception " + e);
+ }
+ return ret;
+ }
+};
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index da566c9..bb3ddcf 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -25,6 +25,7 @@
import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
@@ -51,6 +52,12 @@
private long mCachedNtpElapsedRealtime;
private long mCachedNtpCertainty;
+ private boolean mBackupmode = false;
+ private static String mBackupServer = "";
+ private static int mNtpRetries = 0;
+ private static int mNtpRetriesMax = 0;
+ private static final String BACKUP_SERVER = "persist.backup.ntpServer";
+
private NtpTrustedTime(String server, long timeout) {
if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
mServer = server;
@@ -76,6 +83,23 @@
final String server = secureServer != null ? secureServer : defaultServer;
sSingleton = new NtpTrustedTime(server, timeout);
sContext = context;
+
+ final String sserver_prop = Settings.Global.getString(
+ resolver, Settings.Global.NTP_SERVER_2);
+
+ final String secondServer_prop = ((null != sserver_prop)
+ && (0 < sserver_prop.length()))
+ ? sserver_prop : BACKUP_SERVER;
+
+ final String backupServer = SystemProperties.get(secondServer_prop);
+
+ if ((null != backupServer) && (0 < backupServer.length())) {
+ int retryMax = res.getInteger(com.android.internal.R.integer.config_ntpRetry);
+ if (0 < retryMax) {
+ sSingleton.mNtpRetriesMax = retryMax;
+ sSingleton.mBackupServer = (backupServer.trim()).replace("\"", "");
+ }
+ }
}
return sSingleton;
@@ -84,6 +108,11 @@
@Override
@UnsupportedAppUsage
public boolean forceRefresh() {
+ return hasCache() ? forceSync() : false;
+ }
+
+ @Override
+ public boolean forceSync() {
// We can't do this at initialization time: ConnectivityService might not be running yet.
synchronized (this) {
if (mCM == null) {
@@ -117,13 +146,21 @@
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
- if (client.requestTime(mServer, (int) mTimeout, network)) {
+
+ String targetServer = mServer;
+ if (getBackupmode()) {
+ setBackupmode(false);
+ targetServer = mBackupServer;
+ }
+ if (LOGD) Log.d(TAG, "Ntp Server to access at:" + targetServer);
+ if (client.requestTime(targetServer, (int) mTimeout, network)) {
mHasCache = true;
mCachedNtpTime = client.getNtpTime();
mCachedNtpElapsedRealtime = client.getNtpTimeReference();
mCachedNtpCertainty = client.getRoundTripTime() / 2;
return true;
} else {
+ countInBackupmode();
return false;
}
}
@@ -175,4 +212,32 @@
public long getCachedNtpTimeReference() {
return mCachedNtpElapsedRealtime;
}
+
+ public void setBackupmode(boolean mode) {
+ if (isBackupSupported()) {
+ mBackupmode = mode;
+ }
+ if (LOGD) Log.d(TAG, "setBackupmode() set the backup mode to be:" + mBackupmode);
+ }
+
+ private boolean getBackupmode() {
+ return mBackupmode;
+ }
+
+ private boolean isBackupSupported() {
+ return ((0 < mNtpRetriesMax) &&
+ (null != mBackupServer) &&
+ (0 != mBackupServer.length()));
+ }
+
+ private void countInBackupmode() {
+ if (isBackupSupported()) {
+ mNtpRetries++;
+ if (mNtpRetries >= mNtpRetriesMax) {
+ mNtpRetries = 0;
+ setBackupmode(true);
+ }
+ }
+ if (LOGD) Log.d(TAG, "countInBackupmode() func");
+ }
}
diff --git a/core/java/android/util/SeempLog.java b/core/java/android/util/SeempLog.java
new file mode 100644
index 0000000..3764882
--- /dev/null
+++ b/core/java/android/util/SeempLog.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package android.util;
+
+import com.android.internal.os.RuntimeInit;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.List;
+import java.util.Iterator;
+import android.util.Log;
+import android.provider.Settings;
+
+/**
+ * SeempLog
+ *
+ * @hide
+ */
+public final class SeempLog {
+ private SeempLog() {
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ */
+ public static int record(int api) {
+ return seemp_println_native(api, "");
+ }
+
+ /**
+ * Send a log message to the seemp log.
+ * @param api The api triggering this message.
+ * @param msg The message you would like logged.
+ */
+ public static int record_str(int api, String msg) {
+ if ( msg != null ) {
+ return seemp_println_native(api, msg);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ public static int record_sensor(int api,
+ android.hardware.Sensor sensor) {
+ if ( sensor != null ) {
+ return seemp_println_native(api, "sensor="+sensor.getType());
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1");
+ }
+ }
+
+ public static int record_sensor_rate(int api,
+ android.hardware.Sensor sensor, int rate) {
+ if ( sensor != null ) {
+ return seemp_println_native(api,
+ "sensor="+sensor.getType() + ",rate="+rate);
+ }
+ else {
+ return seemp_println_native(api, "sensor=-1,rate=" + rate);
+ }
+ }
+
+ public static int record_uri(int api, android.net.Uri uri) {
+ if ( uri != null ) {
+ return seemp_println_native(api, "uri, " + uri.toString());
+ }
+ else {
+ return seemp_println_native(api, "uri, null" );
+ }
+ }
+
+ public static int record_vg_layout(int api,
+ android.view.ViewGroup.LayoutParams params) {
+ try {
+ android.view.WindowManager.LayoutParams p =
+ (android.view.WindowManager.LayoutParams) params;
+ if ( p != null ) {
+ return seemp_println_native(api,
+ "window_type=" + p.type + ",window_flag=" + p.flags);
+ }
+ else {
+ return seemp_println_native(api, "");
+ }
+ } catch (ClassCastException cce) {
+ return seemp_println_native(api, "");
+ }
+ }
+
+ /** @hide */ public static native int seemp_println_native(int api, String msg);
+
+ public static final int SEEMP_API_android_provider_Settings__get_ANDROID_ID_ = 7;
+ public static final int SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_ = 96;
+ public static final int SEEMP_API_android_provider_Settings__get_USER_ROTATION_ = 97;
+ public static final int SEEMP_API_android_provider_Settings__get_ADB_ENABLED_ = 98;
+ public static final int SEEMP_API_android_provider_Settings__get_DEBUG_APP_ = 99;
+ public static final int SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_ = 100;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_ = 101;
+ public static final int SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_ = 102;
+ public static final int SEEMP_API_android_provider_Settings__get_ALARM_ALERT_ = 103;
+ public static final int SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_ = 104;
+ public static final int SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_ = 105;
+ public static final int SEEMP_API_android_provider_Settings__get_LOGGING_ID_ = 106;
+ public static final int SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_ = 107;
+ public static final int SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_ = 108;
+ public static final int SEEMP_API_android_provider_Settings__get_FONT_SCALE_ = 109;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_ = 110;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_ = 111;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 112;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 113;
+ public static final int SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_ = 114;
+ public static final int SEEMP_API_android_provider_Settings__get_DIM_SCREEN_ = 115;
+ public static final int SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_ = 116;
+ public static final int SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_ = 117;
+ public static final int SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_ = 118;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_ = 119;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_ = 120;
+ public static final int SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_ = 121;
+ public static final int SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_ = 122;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ = 123;
+ public static final int SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_ = 124;
+ public static final int SEEMP_API_android_provider_Settings__get_DATE_FORMAT_ = 125;
+ public static final int SEEMP_API_android_provider_Settings__get_TIME_12_24_ = 126;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_ = 127;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 128;
+ public static final int SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_ = 129;
+ public static final int SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_ = 130;
+ public static final int SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_ = 131;
+ public static final int SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_ = 132;
+ public static final int SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_ = 133;
+ public static final int SEEMP_API_android_provider_Settings__get_RINGTONE_ = 134;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_ = 135;
+ public static final int SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_ = 136;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_ = 137;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_ = 138;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 139;
+ public static final int SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_ = 140;
+ public static final int SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_ = 141;
+ public static final int SEEMP_API_android_provider_Settings__get_DATA_ROAMING_ = 142;
+ public static final int SEEMP_API_android_provider_Settings__get_HTTP_PROXY_ = 143;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_ = 144;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_ = 145;
+ public static final int SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_ = 146;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_ = 147;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_CELL_ = 148;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_NFC_ = 149;
+ public static final int SEEMP_API_android_provider_Settings__get_RADIO_WIFI_ = 150;
+ public static final int SEEMP_API_android_provider_Settings__get_SYS_PROP_SETTING_VERSION_ = 151;
+ public static final int SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_ = 152;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_ = 153;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_ = 154;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_ = 155;
+ public static final int SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_ = 156;
+ public static final int SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_ = 157;
+ public static final int SEEMP_API_android_provider_Settings__get_VIBRATE_ON_ = 158;
+ public static final int SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_ = 159;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_ = 160;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_ = 161;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_ = 162;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_ = 163;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_RING_ = 164;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_ = 165;
+ public static final int SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_ = 166;
+ public static final int SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_ = 167;
+ public static final int SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_ = 168;
+ public static final int SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_ = 169;
+ public static final int SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_ = 170;
+ public static final int SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_ = 171;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_ = 172;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 173;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 174;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 175;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 176;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_ON_ = 177;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_ = 178;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_DEFAULT_ = 179;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_ = 180;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 181;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_ = 182;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_ = 183;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_ = 184;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_ = 185;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_ = 186;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_ = 187;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 188;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_ = 189;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 190;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 191;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 192;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 193;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 194;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_ = 195;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_ = 196;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_ = 197;
+ public static final int SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 198;
+ public static final int SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_ = 199;
+ public static final int SEEMP_API_android_provider_Settings__put_USER_ROTATION_ = 200;
+ public static final int SEEMP_API_android_provider_Settings__put_ADB_ENABLED_ = 201;
+ public static final int SEEMP_API_android_provider_Settings__put_DEBUG_APP_ = 202;
+ public static final int SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_ = 203;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_ = 204;
+ public static final int SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_ = 205;
+ public static final int SEEMP_API_android_provider_Settings__put_ALARM_ALERT_ = 206;
+ public static final int SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_ = 207;
+ public static final int SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_ = 208;
+ public static final int SEEMP_API_android_provider_Settings__put_ANDROID_ID_ = 209;
+ public static final int SEEMP_API_android_provider_Settings__put_LOGGING_ID_ = 210;
+ public static final int SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_ = 211;
+ public static final int SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_ = 212;
+ public static final int SEEMP_API_android_provider_Settings__put_FONT_SCALE_ = 213;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_ = 214;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_ = 215;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ = 216;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_MANUAL_ = 217;
+ public static final int SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_ = 218;
+ public static final int SEEMP_API_android_provider_Settings__put_DIM_SCREEN_ = 219;
+ public static final int SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_ = 220;
+ public static final int SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_ = 221;
+ public static final int SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_ = 222;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_ = 223;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_ = 224;
+ public static final int SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_ = 225;
+ public static final int SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_ = 226;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ = 227;
+ public static final int SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_ = 228;
+ public static final int SEEMP_API_android_provider_Settings__put_DATE_FORMAT_ = 229;
+ public static final int SEEMP_API_android_provider_Settings__put_TIME_12_24_ = 230;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_ = 231;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ = 232;
+ public static final int SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_ = 233;
+ public static final int SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_ = 234;
+ public static final int SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_ = 235;
+ public static final int SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_ = 236;
+ public static final int SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_ = 237;
+ public static final int SEEMP_API_android_provider_Settings__put_RINGTONE_ = 238;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_ = 239;
+ public static final int SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_ = 240;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_ = 241;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_ = 242;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ = 243;
+ public static final int SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_ = 244;
+ public static final int SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_ = 245;
+ public static final int SEEMP_API_android_provider_Settings__put_DATA_ROAMING_ = 246;
+ public static final int SEEMP_API_android_provider_Settings__put_HTTP_PROXY_ = 247;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_ = 248;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_ = 249;
+ public static final int SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_ = 250;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_ = 251;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_CELL_ = 252;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_NFC_ = 253;
+ public static final int SEEMP_API_android_provider_Settings__put_RADIO_WIFI_ = 254;
+ public static final int SEEMP_API_android_provider_Settings__put_SYS_PROP_SETTING_VERSION_ = 255;
+ public static final int SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_ = 256;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_ = 257;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_ = 258;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_ = 259;
+ public static final int SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_ = 260;
+ public static final int SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_ = 261;
+ public static final int SEEMP_API_android_provider_Settings__put_VIBRATE_ON_ = 262;
+ public static final int SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_ = 263;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_ = 264;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_ = 265;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_ = 266;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_ = 267;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_RING_ = 268;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_ = 269;
+ public static final int SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_ = 270;
+ public static final int SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_ = 271;
+ public static final int SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_ = 272;
+ public static final int SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_ = 273;
+ public static final int SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_ = 274;
+ public static final int SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_ = 275;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_ = 276;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ = 277;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ = 278;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ = 279;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_ = 280;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_ON_ = 281;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_ = 282;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_DEFAULT_ = 283;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_ = 284;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ = 285;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_ = 286;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_ = 287;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_ = 288;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_ = 289;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_ = 290;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_ = 291;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ = 292;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_ = 293;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ = 294;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ = 295;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ = 296;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ = 297;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_ = 298;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_ = 299;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_ = 300;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_ = 301;
+ public static final int SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_ = 302;
+
+ private final static java.util.Map<String,Integer> value_to_get_map;
+ static {
+ value_to_get_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_get_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__get_NOTIFICATION_SOUND_);
+ value_to_get_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__get_DTMF_TONE_WHEN_DIALING_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_get_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_);
+ value_to_get_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__get_SETUP_WIZARD_HAS_RUN_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__get_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_get_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__get_ALARM_ALERT_);
+ value_to_get_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__get_VIBRATE_ON_);
+ value_to_get_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__get_USB_MASS_STORAGE_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_get_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__get_FONT_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_get_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__get_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_get_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_ACCELEROMETER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__get_VOLUME_NOTIFICATION_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_ON_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_IP_);
+ value_to_get_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__get_RADIO_BLUETOOTH_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_get_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__get_VOLUME_RING_);
+ value_to_get_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_SYSTEM_);
+ value_to_get_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__get_SCREEN_OFF_TIMEOUT_);
+ value_to_get_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__get_RADIO_WIFI_);
+ value_to_get_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__get_AUTO_TIME_ZONE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_CAPS_);
+ value_to_get_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__get_WALLPAPER_ACTIVITY_);
+ value_to_get_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_ANIMATOR_DURATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__get_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_VISIBLE_);
+ value_to_get_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__get_VOLUME_VOICE_);
+ value_to_get_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__get_DEBUG_APP_);
+ value_to_get_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_ON_);
+ value_to_get_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__get_TEXT_SHOW_PASSWORD_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_get_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__get_WIFI_SLEEP_POLICY_);
+ value_to_get_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__get_VOLUME_MUSIC_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_get_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__get_DEVICE_PROVISIONED_);
+ value_to_get_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__get_HTTP_PROXY_);
+ value_to_get_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__get_ANDROID_ID_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_get_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__get_END_BUTTON_BEHAVIOR_);
+ value_to_get_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__get_NEXT_ALARM_FORMATTED_);
+ value_to_get_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__get_RADIO_CELL_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_ON_);
+ value_to_get_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_WINDOW_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_get_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__get_BLUETOOTH_DISCOVERABILITY_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS1_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_DNS2_);
+ value_to_get_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__get_SHOW_WEB_SUGGESTIONS_);
+ value_to_get_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__get_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_get_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__get_DATE_FORMAT_);
+ value_to_get_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__get_RADIO_NFC_);
+ value_to_get_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__get_AIRPLANE_MODE_RADIOS_);
+ value_to_get_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_get_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__get_TIME_12_24_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_get_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__get_VOLUME_BLUETOOTH_SCO_);
+ value_to_get_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__get_USER_ROTATION_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_GATEWAY_);
+ value_to_get_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__get_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_get_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__get_SOUND_EFFECTS_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_get_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__get_DATA_ROAMING_);
+ value_to_get_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__get_SETTINGS_CLASSNAME_);
+ value_to_get_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__get_TRANSITION_ANIMATION_SCALE_);
+ value_to_get_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__get_WAIT_FOR_DEBUGGER_);
+ value_to_get_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__get_INSTALL_NON_MARKET_APPS_);
+ value_to_get_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__get_ADB_ENABLED_);
+ value_to_get_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__get_WIFI_USE_STATIC_IP_);
+ value_to_get_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__get_DIM_SCREEN_);
+ value_to_get_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__get_VOLUME_ALARM_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ON_);
+ value_to_get_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__get_WIFI_STATIC_NETMASK_);
+ value_to_get_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__get_NETWORK_PREFERENCE_);
+ value_to_get_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__get_SHOW_PROCESSES_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_REPLACE_);
+ value_to_get_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_get_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__get_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_get_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__get_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_);
+ value_to_get_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__get_USE_GOOGLE_MAIL_);
+ value_to_get_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__get_RINGTONE_);
+ value_to_get_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__get_LOGGING_ID_);
+ value_to_get_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__get_MODE_RINGER_);
+ value_to_get_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__get_MUTE_STREAMS_AFFECTED_);
+ value_to_get_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_get_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__get_TEXT_AUTO_PUNCTUATE_);
+ value_to_get_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_get_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__get_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempGetApiIdFromValue( String v )
+ {
+ Integer result = value_to_get_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+
+ private final static java.util.Map<String,Integer> value_to_put_map;
+ static {
+ value_to_put_map = new java.util.HashMap<String,Integer>( 198 );
+ value_to_put_map.put(Settings.System.NOTIFICATION_SOUND,
+ SEEMP_API_android_provider_Settings__put_NOTIFICATION_SOUND_);
+ value_to_put_map.put(Settings.System.DTMF_TONE_WHEN_DIALING,
+ SEEMP_API_android_provider_Settings__put_DTMF_TONE_WHEN_DIALING_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_MAX_DHCP_RETRY_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_MAX_DHCP_RETRY_COUNT_);
+ value_to_put_map.put(Settings.System.AUTO_TIME,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_);
+ value_to_put_map.put(Settings.System.SETUP_WIZARD_HAS_RUN,
+ SEEMP_API_android_provider_Settings__put_SETUP_WIZARD_HAS_RUN_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.LOCATION_PROVIDERS_ALLOWED,
+ SEEMP_API_android_provider_Settings__put_LOCATION_PROVIDERS_ALLOWED_);
+ value_to_put_map.put(Settings.System.ALARM_ALERT,
+ SEEMP_API_android_provider_Settings__put_ALARM_ALERT_);
+ value_to_put_map.put(Settings.System.VIBRATE_ON,
+ SEEMP_API_android_provider_Settings__put_VIBRATE_ON_);
+ value_to_put_map.put(Settings.System.USB_MASS_STORAGE_ENABLED,
+ SEEMP_API_android_provider_Settings__put_USB_MASS_STORAGE_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_DELAY_MS_);
+ value_to_put_map.put(Settings.System.FONT_SCALE,
+ SEEMP_API_android_provider_Settings__put_FONT_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_AP_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_AP_COUNT_);
+ value_to_put_map.put(Settings.System.ALWAYS_FINISH_ACTIVITIES,
+ SEEMP_API_android_provider_Settings__put_ALWAYS_FINISH_ACTIVITIES_);
+ value_to_put_map.put(Settings.System.ACCELEROMETER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_ACCELEROMETER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.VOLUME_NOTIFICATION,
+ SEEMP_API_android_provider_Settings__put_VOLUME_NOTIFICATION_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_ON,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_ON_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_IP_);
+ value_to_put_map.put(Settings.System.RADIO_BLUETOOTH,
+ SEEMP_API_android_provider_Settings__put_RADIO_BLUETOOTH_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_);
+ value_to_put_map.put(Settings.System.VOLUME_RING,
+ SEEMP_API_android_provider_Settings__put_VOLUME_RING_);
+ value_to_put_map.put(Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.VOLUME_SYSTEM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_SYSTEM_);
+ value_to_put_map.put(Settings.System.SCREEN_OFF_TIMEOUT,
+ SEEMP_API_android_provider_Settings__put_SCREEN_OFF_TIMEOUT_);
+ value_to_put_map.put(Settings.System.RADIO_WIFI,
+ SEEMP_API_android_provider_Settings__put_RADIO_WIFI_);
+ value_to_put_map.put(Settings.System.AUTO_TIME_ZONE,
+ SEEMP_API_android_provider_Settings__put_AUTO_TIME_ZONE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_CAPS,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_CAPS_);
+ value_to_put_map.put(Settings.System.WALLPAPER_ACTIVITY,
+ SEEMP_API_android_provider_Settings__put_WALLPAPER_ACTIVITY_);
+ value_to_put_map.put(Settings.System.ANIMATOR_DURATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_ANIMATOR_DURATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_NUM_OPEN_NETWORKS_KEPT,
+ SEEMP_API_android_provider_Settings__put_WIFI_NUM_OPEN_NETWORKS_KEPT_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_VISIBLE,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_VISIBLE_);
+ value_to_put_map.put(Settings.System.VOLUME_VOICE,
+ SEEMP_API_android_provider_Settings__put_VOLUME_VOICE_);
+ value_to_put_map.put(Settings.System.DEBUG_APP,
+ SEEMP_API_android_provider_Settings__put_DEBUG_APP_);
+ value_to_put_map.put(Settings.System.WIFI_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_ON_);
+ value_to_put_map.put(Settings.System.TEXT_SHOW_PASSWORD,
+ SEEMP_API_android_provider_Settings__put_TEXT_SHOW_PASSWORD_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_);
+ value_to_put_map.put(Settings.System.WIFI_SLEEP_POLICY,
+ SEEMP_API_android_provider_Settings__put_WIFI_SLEEP_POLICY_);
+ value_to_put_map.put(Settings.System.VOLUME_MUSIC,
+ SEEMP_API_android_provider_Settings__put_VOLUME_MUSIC_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_LAST_UPDATE,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_LAST_UPDATE_);
+ value_to_put_map.put(Settings.System.DEVICE_PROVISIONED,
+ SEEMP_API_android_provider_Settings__put_DEVICE_PROVISIONED_);
+ value_to_put_map.put(Settings.System.HTTP_PROXY,
+ SEEMP_API_android_provider_Settings__put_HTTP_PROXY_);
+ value_to_put_map.put(Settings.System.ANDROID_ID,
+ SEEMP_API_android_provider_Settings__put_ANDROID_ID_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_MAX_AP_CHECKS,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_MAX_AP_CHECKS_);
+ value_to_put_map.put(Settings.System.END_BUTTON_BEHAVIOR,
+ SEEMP_API_android_provider_Settings__put_END_BUTTON_BEHAVIOR_);
+ value_to_put_map.put(Settings.System.NEXT_ALARM_FORMATTED,
+ SEEMP_API_android_provider_Settings__put_NEXT_ALARM_FORMATTED_);
+ value_to_put_map.put(Settings.System.RADIO_CELL,
+ SEEMP_API_android_provider_Settings__put_RADIO_CELL_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_ENABLED,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_ON,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_ON_);
+ value_to_put_map.put(Settings.System.WINDOW_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_WINDOW_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_);
+ value_to_put_map.put(Settings.System.BLUETOOTH_DISCOVERABILITY,
+ SEEMP_API_android_provider_Settings__put_BLUETOOTH_DISCOVERABILITY_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS1,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS1_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_DNS2,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_DNS2_);
+ value_to_put_map.put(Settings.System.HAPTIC_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_HAPTIC_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.SHOW_WEB_SUGGESTIONS,
+ SEEMP_API_android_provider_Settings__put_SHOW_WEB_SUGGESTIONS_);
+ value_to_put_map.put(Settings.System.PARENTAL_CONTROL_REDIRECT_URL,
+ SEEMP_API_android_provider_Settings__put_PARENTAL_CONTROL_REDIRECT_URL_);
+ value_to_put_map.put(Settings.System.DATE_FORMAT,
+ SEEMP_API_android_provider_Settings__put_DATE_FORMAT_);
+ value_to_put_map.put(Settings.System.RADIO_NFC,
+ SEEMP_API_android_provider_Settings__put_RADIO_NFC_);
+ value_to_put_map.put(Settings.System.AIRPLANE_MODE_RADIOS,
+ SEEMP_API_android_provider_Settings__put_AIRPLANE_MODE_RADIOS_);
+ value_to_put_map.put(Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED,
+ SEEMP_API_android_provider_Settings__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_);
+ value_to_put_map.put(Settings.System.TIME_12_24,
+ SEEMP_API_android_provider_Settings__put_TIME_12_24_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_);
+ value_to_put_map.put(Settings.System.VOLUME_BLUETOOTH_SCO,
+ SEEMP_API_android_provider_Settings__put_VOLUME_BLUETOOTH_SCO_);
+ value_to_put_map.put(Settings.System.USER_ROTATION,
+ SEEMP_API_android_provider_Settings__put_USER_ROTATION_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_GATEWAY,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_GATEWAY_);
+ value_to_put_map.put(Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+ SEEMP_API_android_provider_Settings__put_STAY_ON_WHILE_PLUGGED_IN_);
+ value_to_put_map.put(Settings.System.SOUND_EFFECTS_ENABLED,
+ SEEMP_API_android_provider_Settings__put_SOUND_EFFECTS_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_PING_COUNT,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_PING_COUNT_);
+ value_to_put_map.put(Settings.System.DATA_ROAMING,
+ SEEMP_API_android_provider_Settings__put_DATA_ROAMING_);
+ value_to_put_map.put(Settings.System.SETTINGS_CLASSNAME,
+ SEEMP_API_android_provider_Settings__put_SETTINGS_CLASSNAME_);
+ value_to_put_map.put(Settings.System.TRANSITION_ANIMATION_SCALE,
+ SEEMP_API_android_provider_Settings__put_TRANSITION_ANIMATION_SCALE_);
+ value_to_put_map.put(Settings.System.WAIT_FOR_DEBUGGER,
+ SEEMP_API_android_provider_Settings__put_WAIT_FOR_DEBUGGER_);
+ value_to_put_map.put(Settings.System.INSTALL_NON_MARKET_APPS,
+ SEEMP_API_android_provider_Settings__put_INSTALL_NON_MARKET_APPS_);
+ value_to_put_map.put(Settings.System.ADB_ENABLED,
+ SEEMP_API_android_provider_Settings__put_ADB_ENABLED_);
+ value_to_put_map.put(Settings.System.WIFI_USE_STATIC_IP,
+ SEEMP_API_android_provider_Settings__put_WIFI_USE_STATIC_IP_);
+ value_to_put_map.put(Settings.System.DIM_SCREEN,
+ SEEMP_API_android_provider_Settings__put_DIM_SCREEN_);
+ value_to_put_map.put(Settings.System.VOLUME_ALARM,
+ SEEMP_API_android_provider_Settings__put_VOLUME_ALARM_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ON_);
+ value_to_put_map.put(Settings.System.WIFI_STATIC_NETMASK,
+ SEEMP_API_android_provider_Settings__put_WIFI_STATIC_NETMASK_);
+ value_to_put_map.put(Settings.System.NETWORK_PREFERENCE,
+ SEEMP_API_android_provider_Settings__put_NETWORK_PREFERENCE_);
+ value_to_put_map.put(Settings.System.SHOW_PROCESSES,
+ SEEMP_API_android_provider_Settings__put_SHOW_PROCESSES_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_REPLACE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_REPLACE_);
+ value_to_put_map.put(Settings.System.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ SEEMP_API_android_provider_Settings__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_);
+ value_to_put_map.put(Settings.System.APPEND_FOR_LAST_AUDIBLE,
+ SEEMP_API_android_provider_Settings__put_APPEND_FOR_LAST_AUDIBLE_);
+ value_to_put_map.put(Settings.System.SHOW_GTALK_SERVICE_STATUS,
+ SEEMP_API_android_provider_Settings__put_SHOW_GTALK_SERVICE_STATUS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_);
+ value_to_put_map.put(Settings.System.USE_GOOGLE_MAIL,
+ SEEMP_API_android_provider_Settings__put_USE_GOOGLE_MAIL_);
+ value_to_put_map.put(Settings.System.RINGTONE,
+ SEEMP_API_android_provider_Settings__put_RINGTONE_);
+ value_to_put_map.put(Settings.System.LOGGING_ID,
+ SEEMP_API_android_provider_Settings__put_LOGGING_ID_);
+ value_to_put_map.put(Settings.System.MODE_RINGER,
+ SEEMP_API_android_provider_Settings__put_MODE_RINGER_);
+ value_to_put_map.put(Settings.System.MUTE_STREAMS_AFFECTED,
+ SEEMP_API_android_provider_Settings__put_MUTE_STREAMS_AFFECTED_);
+ value_to_put_map.put(Settings.System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE,
+ SEEMP_API_android_provider_Settings__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_);
+ value_to_put_map.put(Settings.System.TEXT_AUTO_PUNCTUATE,
+ SEEMP_API_android_provider_Settings__put_TEXT_AUTO_PUNCTUATE_);
+ value_to_put_map.put(Settings.System.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ SEEMP_API_android_provider_Settings__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_);
+ value_to_put_map.put(Settings.System.SCREEN_BRIGHTNESS_MODE,
+ SEEMP_API_android_provider_Settings__put_SCREEN_BRIGHTNESS_MODE_);
+ }
+
+ public static int getSeempPutApiIdFromValue( String v )
+ {
+ Integer result = value_to_put_map.get( v );
+ if (result == null)
+ {
+ result = -1;
+ }
+ return result;
+ }
+}
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index f7077bb..c18e6be 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -222,6 +222,26 @@
}
/**
+ * Add a log to the stats log.
+ *
+ * @param id The id of the atom
+ * @param params The parameters of the atom's message.
+ */
+ public static void write(int id, @NonNull Object... params) {
+ switch (id) {
+ case PERMISSION_GRANT_REQUEST_RESULT_REPORTED:
+ write(id, (long) params[0], (int) params[1], (String) params[2], (String) params[3],
+ (boolean) params[4], (int) params[5]);
+ break;
+ case DATA_STALL_EVENT:
+ // Refer to the defintion in frameworks/base/cmds/statsd/src/atoms.proto.
+ write(id, (int) params[0], (int) params[1], (int) params[2], (byte[]) params[3],
+ (byte[]) params[4], (byte[]) params[5]);
+ break;
+ }
+ }
+
+ /**
* Write an event to stats log using the raw format.
*
* @param buffer The encoded buffer of data to write..
diff --git a/core/java/android/util/TrustedTime.java b/core/java/android/util/TrustedTime.java
index c78665d..0ae5dec 100644
--- a/core/java/android/util/TrustedTime.java
+++ b/core/java/android/util/TrustedTime.java
@@ -29,6 +29,12 @@
* Force update with an external trusted time source, returning {@code true}
* when successful.
*/
+ public boolean forceSync();
+
+ /**
+ * Force update the cached time with an external trusted time source,
+ * returning {@code true} when successful.
+ */
@UnsupportedAppUsage
public boolean forceRefresh();
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 71c8e98..fd00f9e 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -28,7 +28,10 @@
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.Signature;
import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.Slog;
import android.util.jar.StrictJarFile;
+import android.util.BoostFramework;
import com.android.internal.util.ArrayUtils;
@@ -46,6 +49,9 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.ZipEntry;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* Facade class that takes care of the details of APK verification on
@@ -57,6 +63,12 @@
private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
+ private static final String TAG = "ApkSignatureVerifier";
+ // multithread verification
+ private static final int NUMBER_OF_CORES =
+ Runtime.getRuntime().availableProcessors() >= 4 ? 4 : Runtime.getRuntime().availableProcessors() ;
+ private static BoostFramework sPerfBoost = null;
+ private static boolean sIsPerfLockAcquired = false;
/**
* Verifies the provided APK and returns the certificates associated with each signer.
*
@@ -160,31 +172,44 @@
private static PackageParser.SigningDetails verifyV1Signature(
String apkPath, boolean verifyFull)
throws PackageParserException {
- StrictJarFile jarFile = null;
-
+ int objectNumber = verifyFull ? NUMBER_OF_CORES : 1;
+ StrictJarFile[] jarFile = new StrictJarFile[objectNumber];
+ final ArrayMap<String, StrictJarFile> strictJarFiles = new ArrayMap<String, StrictJarFile>();
try {
final Certificate[][] lastCerts;
final Signature[] lastSigs;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
+ if (sPerfBoost == null) {
+ sPerfBoost = new BoostFramework();
+ }
+ if (sPerfBoost != null && !sIsPerfLockAcquired && verifyFull) {
+ //Use big enough number here to hold the perflock for entire PackageInstall session
+ sPerfBoost.perfHint(BoostFramework.VENDOR_HINT_PACKAGE_INSTALL_BOOST,
+ null, Integer.MAX_VALUE, -1);
+ Slog.d(TAG, "Perflock acquired for PackageInstall ");
+ sIsPerfLockAcquired = true;
+ }
// we still pass verify = true to ctor to collect certs, even though we're not checking
// the whole jar.
- jarFile = new StrictJarFile(
- apkPath,
- true, // collect certs
- verifyFull); // whether to reject APK with stripped v2 signatures (b/27887819)
+ for (int i = 0; i < objectNumber; i++) {
+ jarFile[i] = new StrictJarFile(
+ apkPath,
+ true, // collect certs
+ verifyFull); // whether to reject APK with stripped v2 signatures (b/27887819)
+ }
final List<ZipEntry> toVerify = new ArrayList<>();
// Gather certs from AndroidManifest.xml, which every APK must have, as an optimization
// to not need to verify the whole APK when verifyFUll == false.
- final ZipEntry manifestEntry = jarFile.findEntry(
+ final ZipEntry manifestEntry = jarFile[0].findEntry(
PackageParser.ANDROID_MANIFEST_FILENAME);
if (manifestEntry == null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Package " + apkPath + " has no manifest");
}
- lastCerts = loadCertificates(jarFile, manifestEntry);
+ lastCerts = loadCertificates(jarFile[0], manifestEntry);
if (ArrayUtils.isEmpty(lastCerts)) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
+ apkPath + " has no certificates at entry "
@@ -194,7 +219,7 @@
// fully verify all contents, except for AndroidManifest.xml and the META-INF/ files.
if (verifyFull) {
- final Iterator<ZipEntry> i = jarFile.iterator();
+ final Iterator<ZipEntry> i = jarFile[0].iterator();
while (i.hasNext()) {
final ZipEntry entry = i.next();
if (entry.isDirectory()) continue;
@@ -205,24 +230,93 @@
toVerify.add(entry);
}
-
+ class VerificationData {
+ public Exception exception;
+ public int exceptionFlag;
+ public boolean wait;
+ public int index;
+ public Object objWaitAll;
+ public boolean shutDown;
+ }
+ VerificationData vData = new VerificationData();
+ vData.objWaitAll = new Object();
+ final ThreadPoolExecutor verificationExecutor = new ThreadPoolExecutor(
+ NUMBER_OF_CORES,
+ NUMBER_OF_CORES,
+ 1,/*keep alive time*/
+ TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>());
for (ZipEntry entry : toVerify) {
- final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
- if (ArrayUtils.isEmpty(entryCerts)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "Package " + apkPath + " has no certificates at entry "
- + entry.getName());
- }
+ Runnable verifyTask = new Runnable(){
+ public void run() {
+ try {
+ if (vData.exceptionFlag != 0 ) {
+ Slog.w(TAG, "VerifyV1 exit with exception " + vData.exceptionFlag);
+ return;
+ }
+ String tid = Long.toString(Thread.currentThread().getId());
+ StrictJarFile tempJarFile;
+ synchronized (strictJarFiles) {
+ tempJarFile = strictJarFiles.get(tid);
+ if (tempJarFile == null) {
+ if (vData.index >= NUMBER_OF_CORES) {
+ vData.index = 0;
+ }
+ tempJarFile = jarFile[vData.index++];
+ strictJarFiles.put(tid, tempJarFile);
+ }
+ }
+ final Certificate[][] entryCerts = loadCertificates(tempJarFile, entry);
+ if (ArrayUtils.isEmpty(entryCerts)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Package " + apkPath + " has no certificates at entry "
+ + entry.getName());
+ }
- // make sure all entries use the same signing certs
- final Signature[] entrySigs = convertToSignatures(entryCerts);
- if (!Signature.areExactMatch(lastSigs, entrySigs)) {
- throw new PackageParserException(
- INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Package " + apkPath + " has mismatched certificates at entry "
- + entry.getName());
+ // make sure all entries use the same signing certs
+ final Signature[] entrySigs = convertToSignatures(entryCerts);
+ if (!Signature.areExactMatch(lastSigs, entrySigs)) {
+ throw new PackageParserException(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Package " + apkPath + " has mismatched certificates at entry "
+ + entry.getName());
+ }
+ } catch (GeneralSecurityException e) {
+ synchronized (vData.objWaitAll) {
+ vData.exceptionFlag = INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+ vData.exception = e;
+ }
+ } catch (PackageParserException e) {
+ synchronized (vData.objWaitAll) {
+ vData.exceptionFlag = INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+ vData.exception = e;
+ }
+ }
+ }};
+ synchronized (vData.objWaitAll) {
+ if (vData.exceptionFlag == 0) {
+ verificationExecutor.execute(verifyTask);
+ }
}
}
+ vData.wait = true;
+ verificationExecutor.shutdown();
+ while (vData.wait) {
+ try {
+ if (vData.exceptionFlag != 0 && !vData.shutDown) {
+ Slog.w(TAG, "verifyV1 Exception " + vData.exceptionFlag);
+ verificationExecutor.shutdownNow();
+ vData.shutDown = true;
+ }
+ vData.wait = !verificationExecutor.awaitTermination(50,
+ TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Slog.w(TAG,"VerifyV1 interrupted while awaiting all threads done...");
+ }
+ }
+ if (vData.exceptionFlag != 0)
+ throw new PackageParserException(vData.exceptionFlag,
+ "Failed to collect certificates from " + apkPath, vData.exception);
}
return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
} catch (GeneralSecurityException e) {
@@ -232,8 +326,16 @@
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath, e);
} finally {
+ if (sIsPerfLockAcquired && sPerfBoost != null) {
+ sPerfBoost.perfLockRelease();
+ sIsPerfLockAcquired = false;
+ Slog.d(TAG, "Perflock released for PackageInstall ");
+ }
+ strictJarFiles.clear();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- closeQuietly(jarFile);
+ for (int i = 0; i < objectNumber ; i++) {
+ closeQuietly(jarFile[i]);
+ }
}
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index e95b5ca..5643068 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -84,6 +84,7 @@
// Prints debug messages about jank which was detected (low volume).
private static final boolean DEBUG_JANK = false;
+ private static final boolean OPTS_INPUT = true;
// Prints debug messages about every frame and callback registered (high volume).
private static final boolean DEBUG_FRAMES = false;
@@ -151,6 +152,11 @@
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
+ private static final int MOTION_EVENT_ACTION_DOWN = 0;
+ private static final int MOTION_EVENT_ACTION_UP = 1;
+ private static final int MOTION_EVENT_ACTION_MOVE = 2;
+ private static final int MOTION_EVENT_ACTION_CANCEL = 3;
+
// All frame callbacks posted by applications have this token.
private static final Object FRAME_CALLBACK_TOKEN = new Object() {
public String toString() { return "FRAME_CALLBACK_TOKEN"; }
@@ -181,7 +187,11 @@
private long mFrameIntervalNanos;
private boolean mDebugPrintNextFrameTimeDelta;
private int mFPSDivisor = 1;
-
+ private int mTouchMoveNum = -1;
+ private int mMotionEventType = -1;
+ private boolean mConsumedMove = false;
+ private boolean mConsumedDown = false;
+ private boolean mIsVsyncScheduled = false;
/**
* Contains information about the current frame for jank-tracking,
* mainly timings of key events along with a bit of metadata about
@@ -296,6 +306,16 @@
}
/**
+ * {@hide}
+ */
+ public void setMotionEventInfo(int motionEventType, int touchMoveNum) {
+ synchronized(this) {
+ mTouchMoveNum = touchMoveNum;
+ mMotionEventType = motionEventType;
+ }
+ }
+
+ /**
* @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
* @hide
*/
@@ -621,6 +641,47 @@
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
+ if (OPTS_INPUT) {
+ if ((!mIsVsyncScheduled) &&
+ ((System.nanoTime() - mLastFrameTimeNanos) > mFrameIntervalNanos)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "scheduleFrameLocked-mMotionEventType:"
+ + mMotionEventType + " mTouchMoveNum:" + mTouchMoveNum
+ + " mConsumedDown:" + mConsumedDown + " mConsumedMove:"
+ + mConsumedMove);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ synchronized(this) {
+ switch(mMotionEventType) {
+ case MOTION_EVENT_ACTION_DOWN:
+ mConsumedMove = false;
+ if (!mConsumedDown) {
+ Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtFrontOfQueue(msg);
+ mConsumedDown = true;
+ return;
+ }
+ break;
+ case MOTION_EVENT_ACTION_MOVE:
+ mConsumedDown = false;
+ if ((mTouchMoveNum == 1) && !mConsumedMove) {
+ Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtFrontOfQueue(msg);
+ mConsumedMove = true;
+ return;
+ }
+ break;
+ case MOTION_EVENT_ACTION_UP:
+ case MOTION_EVENT_ACTION_CANCEL:
+ mConsumedMove = false;
+ mConsumedDown = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
@@ -659,6 +720,7 @@
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
+ mIsVsyncScheduled = false;
if (!mFrameScheduled) {
return; // no work to do
}
@@ -825,6 +887,7 @@
@UnsupportedAppUsage
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
+ mIsVsyncScheduled = true;
}
private boolean isRunningOnLooperThreadLocked() {
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index ed8492e..9b1519a 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -44,6 +44,7 @@
// Map from InputEvent sequence numbers to dispatcher sequence numbers.
private final SparseIntArray mSeqMap = new SparseIntArray();
+ Choreographer mChoreographer;
private static native long nativeInit(WeakReference<InputEventReceiver> receiver,
InputChannel inputChannel, MessageQueue messageQueue);
@@ -199,6 +200,19 @@
onBatchedInputEventPending();
}
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchMotionEventInfo(int motionEventType, int touchMoveNum) {
+ try {
+ if (mChoreographer == null)
+ mChoreographer = Choreographer.getInstance();
+
+ if (mChoreographer != null)
+ mChoreographer.setMotionEventInfo(motionEventType, touchMoveNum);
+ } catch (Exception e) {
+ Log.e(TAG, "cannot invoke setMotionEventInfo.");
+ }
+ }
public static interface Factory {
public InputEventReceiver createInputEventReceiver(
InputChannel inputChannel, Looper looper);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8dd475e..b6c3476 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -347,6 +347,9 @@
*/
private static final int SURFACE_OPAQUE = 0x02;
+ /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
+ * these are different from the logical display ids used elsewhere in the framework */
+
// Display power modes.
/**
* Display power mode off: used while blanking the screen.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1599afb..0cb5570 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13973,6 +13973,7 @@
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
+ android.util.SeempLog.record(3);
// Defensive cleanup for new gesture
stopNestedScroll();
}
@@ -14662,6 +14663,7 @@
* @param event the KeyEvent object that defines the button action
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(4);
if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
@@ -14719,6 +14721,7 @@
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ android.util.SeempLog.record(5);
if (KeyEvent.isConfirmKey(keyCode)) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
@@ -15327,6 +15330,7 @@
* @return True if the event was handled, false otherwise.
*/
public boolean onTouchEvent(MotionEvent event) {
+ android.util.SeempLog.record(3);
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20dc234..faf394e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -618,6 +618,8 @@
}
private String mTag = TAG;
+ boolean mHaveMoveEvent = false;
+
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession());
}
@@ -5731,6 +5733,12 @@
mAttachInfo.mUnbufferedDispatchRequested = false;
mAttachInfo.mHandlingPointerEvent = true;
boolean handled = mView.dispatchPointerEvent(event);
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_MOVE) {
+ mHaveMoveEvent = true;
+ } else if (action == MotionEvent.ACTION_UP) {
+ mHaveMoveEvent = false;
+ }
maybeUpdatePointerIcon(event);
maybeUpdateTooltip(event);
mAttachInfo.mHandlingPointerEvent = false;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index c349443..66c7b05 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -91,12 +91,14 @@
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(383,params);
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
+ android.util.SeempLog.record_vg_layout(384,params);
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4db6308..605f98a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -317,7 +317,9 @@
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {}
+ GeolocationPermissions.Callback callback) {
+ android.util.SeempLog.record(54);
+ }
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
old mode 100644
new mode 100755
index 6d60366..c59fac3
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
+import android.os.SystemProperties;
import android.os.Trace;
import android.text.Editable;
import android.text.InputType;
@@ -114,6 +115,10 @@
@SuppressWarnings("UnusedDeclaration")
private static final String TAG = "AbsListView";
+ private static final boolean OPTS_INPUT = true;
+ private static final double MOVE_TOUCH_SLOP = 0.6;
+ private static final double TOUCH_SLOP_MIN = 0.6;
+ private static final double TOUCH_SLOP_MAX = 1.0;
/**
* Disables the transcript mode.
@@ -782,6 +787,10 @@
*/
private boolean mIsDetaching;
+ private boolean mIsFirstTouchMoveEvent = false;
+ private int mMoveAcceleration;
+ private int mNumTouchMoveEvent = 0;
+
/**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
@@ -925,6 +934,20 @@
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
mVerticalScrollFactor = configuration.getScaledVerticalScrollFactor();
+ if (OPTS_INPUT) {
+ double touchslopprop = MOVE_TOUCH_SLOP;
+ if (touchslopprop > 0) {
+ if (touchslopprop < TOUCH_SLOP_MIN) {
+ mMoveAcceleration = (int)(mTouchSlop * TOUCH_SLOP_MIN);
+ } else if ((touchslopprop >= TOUCH_SLOP_MIN) && (touchslopprop < TOUCH_SLOP_MAX)){
+ mMoveAcceleration = (int)(mTouchSlop * touchslopprop);
+ } else {
+ mMoveAcceleration = mTouchSlop;
+ }
+ } else {
+ mMoveAcceleration = mTouchSlop;
+ }
+ }
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mOverscrollDistance = configuration.getScaledOverscrollDistance();
@@ -3548,7 +3571,18 @@
final int deltaY = y - mMotionY;
final int distance = Math.abs(deltaY);
final boolean overscroll = mScrollY != 0;
- if ((overscroll || distance > mTouchSlop) &&
+ boolean isFarEnough = false;
+ if (OPTS_INPUT) {
+ if (mIsFirstTouchMoveEvent) {
+ isFarEnough = distance > mMoveAcceleration;
+ } else {
+ isFarEnough = distance > mTouchSlop;
+ }
+ } else {
+ isFarEnough = distance > mTouchSlop;
+ }
+
+ if ((overscroll || isFarEnough) &&
(getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
createScrollingCache();
if (overscroll) {
@@ -3556,7 +3590,11 @@
mMotionCorrection = 0;
} else {
mTouchMode = TOUCH_MODE_SCROLL;
- mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
+ if (mIsFirstTouchMoveEvent) {
+ mMotionCorrection = deltaY > 0 ? mMoveAcceleration : -mMoveAcceleration;
+ } else {
+ mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop;
+ }
}
removeCallbacks(mPendingCheckForLongPress);
setPressed(false);
@@ -3873,21 +3911,38 @@
switch (actionMasked) {
case MotionEvent.ACTION_DOWN: {
onTouchDown(ev);
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
break;
}
case MotionEvent.ACTION_MOVE: {
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent++;
+ if (mNumTouchMoveEvent == 1) {
+ mIsFirstTouchMoveEvent = true;
+ } else {
+ mIsFirstTouchMoveEvent = false;
+ }
+ }
onTouchMove(ev, vtev);
break;
}
case MotionEvent.ACTION_UP: {
onTouchUp(ev);
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
break;
}
case MotionEvent.ACTION_CANCEL: {
onTouchCancel();
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
break;
}
@@ -3903,6 +3958,9 @@
mMotionPosition = motionPosition;
}
mLastY = y;
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
break;
}
@@ -3924,6 +3982,9 @@
mMotionPosition = motionPosition;
}
mLastY = y;
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
break;
}
}
@@ -4101,6 +4162,11 @@
}
mSelector.setHotspot(x, ev.getY());
}
+ if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
+ if (!post(performClick)) {
+ performClick.run();
+ }
+ }
if (mTouchModeReset != null) {
removeCallbacks(mTouchModeReset);
}
@@ -4111,9 +4177,6 @@
mTouchMode = TOUCH_MODE_REST;
child.setPressed(false);
setPressed(false);
- if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
- performClick.run();
- }
}
};
postDelayed(mTouchModeReset,
@@ -4506,6 +4569,9 @@
switch (actionMasked) {
case MotionEvent.ACTION_DOWN: {
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
int touchMode = mTouchMode;
if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
mMotionCorrection = 0;
@@ -4540,6 +4606,14 @@
}
case MotionEvent.ACTION_MOVE: {
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent++;
+ if (mNumTouchMoveEvent == 1) {
+ mIsFirstTouchMoveEvent = true;
+ } else {
+ mIsFirstTouchMoveEvent = false;
+ }
+ }
switch (mTouchMode) {
case TOUCH_MODE_DOWN:
int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -4560,6 +4634,9 @@
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
mTouchMode = TOUCH_MODE_REST;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
@@ -4569,6 +4646,9 @@
}
case MotionEvent.ACTION_POINTER_UP: {
+ if (OPTS_INPUT) {
+ mNumTouchMoveEvent = 0;
+ }
onSecondaryPointerUp(ev);
break;
}
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index e7a96be..46b1c59 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -23,6 +23,7 @@
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.os.SystemProperties;
/**
* This class encapsulates scrolling with the ability to overshoot the bounds
@@ -546,6 +547,7 @@
static class SplineOverScroller {
// Initial position
+ private Context mContext;
private int mStart;
// Current position
@@ -647,6 +649,7 @@
}
SplineOverScroller(Context context) {
+ mContext = context;
mFinished = true;
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
@@ -848,7 +851,7 @@
}
void notifyEdgeReached(int start, int end, int over) {
- // mState is used to detect successive notifications
+ // mState is used to detect successive notifications
if (mState == SPLINE) {
mOver = over;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
@@ -955,8 +958,8 @@
final float t = (float) (currentTime) / mDuration;
final float t2 = t * t;
final float sign = Math.signum(mVelocity);
- distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2);
- mCurrVelocity = sign * mOver * 6.0f * (- t + t2);
+ distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2);
+ mCurrVelocity = sign * mOver * 6.0f * (- t + t2);
break;
}
}
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 229eaf0..013592a 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -24,7 +24,6 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-
/**
* <p>This class encapsulates scrolling. You can use scrollers ({@link Scroller}
* or {@link OverScroller}) to collect the data you need to produce a scrolling
@@ -64,6 +63,7 @@
@UnsupportedAppUsage
private final Interpolator mInterpolator;
+ private Context mContext;
private int mMode;
private int mStartX;
@@ -175,6 +175,7 @@
*/
public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
mFinished = true;
+ mContext = context;
if (interpolator == null) {
mInterpolator = new ViscousFluidInterpolator();
} else {
diff --git a/core/java/com/android/internal/app/ActivityTrigger.java b/core/java/com/android/internal/app/ActivityTrigger.java
new file mode 100644
index 0000000..dbcb13f4
--- /dev/null
+++ b/core/java/com/android/internal/app/ActivityTrigger.java
@@ -0,0 +1,101 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.internal.app;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.util.Log;
+
+public class ActivityTrigger
+{
+ private static final String TAG = "ActivityTrigger";
+
+ /** @hide */
+ public ActivityTrigger() {
+ //Log.d(TAG, "ActivityTrigger initialized");
+ }
+
+ /** @hide */
+ protected void finalize() {
+ native_at_deinit();
+ }
+
+ /** @hide */
+ public void activityStartTrigger(ApplicationInfo appInfo, int pid) {
+ int reserved =0;
+ String activity = null;
+ activity = appInfo.packageName + "/" + appInfo.processName + "/" +
+ appInfo.longVersionCode + "/" + pid;
+ native_at_startApp(activity, reserved);
+ }
+
+ /** @hide */
+ public void activityResumeTrigger(Intent intent, ActivityInfo acInfo,
+ ApplicationInfo appInfo, boolean IsInFullScreen) {
+ ComponentName cn = intent.getComponent();
+ String activity = null;
+
+ if (cn != null)
+ activity = cn.flattenToString() + "/" + appInfo.versionCode;
+ native_at_resumeActivity(activity);
+ }
+
+ public void activityPauseTrigger(Intent intent, ActivityInfo acInfo, ApplicationInfo appInfo) {
+ ComponentName cn = intent.getComponent();
+ String activity = null;
+ Log.d(TAG, "ActivityTrigger activityPauseTrigger ");
+ if (null != cn && null != appInfo)
+ activity = cn.flattenToString() + "/" + appInfo.versionCode;
+ native_at_pauseActivity(activity);
+ }
+
+ public void activityStopTrigger(Intent intent, ActivityInfo acInfo, ApplicationInfo appInfo) {
+ ComponentName cn = intent.getComponent();
+ String activity = null;
+ Log.d(TAG, "ActivityTrigger activityStopTrigger ");
+ if (null != cn && null != appInfo)
+ activity = cn.flattenToString() + "/" + appInfo.versionCode;
+ native_at_stopActivity(activity);
+ }
+
+ public float activityMiscTrigger(int func, String activity, int flag, int type) {
+ return native_at_miscActivity(func, activity, flag, type);
+ }
+
+ private native int native_at_startActivity(String activity, int flags);
+ private native int native_at_startApp(String activity, int flags);
+ private native void native_at_resumeActivity(String activity);
+ private native void native_at_pauseActivity(String activity);
+ private native void native_at_stopActivity(String activity);
+ private native void native_at_deinit();
+ private native float native_at_miscActivity(int func, String activity, int flag, int type);
+}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 363e549..8797d1f 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -184,12 +184,17 @@
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
-
try {
System.loadLibrary("sfplugin_ccodec");
} catch (Error | RuntimeException e) {
// tolerate missing sfplugin_ccodec which is only present on Codec 2 devices
}
+
+ try {
+ System.loadLibrary("qti_performance");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "Couldn't load qti_performance");
+ }
}
native private static void nativePreloadAppProcessHALs();
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 897b982..326094e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -88,4 +88,6 @@
in byte[] recoveryKeyBlob,
in List<WrappedApplicationKey> applicationKeys);
void closeSession(in String sessionId);
+ void sanitizePassword();
+ String getPassword();
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b534213..8b88959 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -693,6 +693,17 @@
reportEnabledTrustAgentsChanged(userHandle);
}
+ /**
+ * clears stored password.
+ */
+ public void sanitizePassword() {
+ try {
+ getLockSettings().sanitizePassword();
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't sanitize password" + re);
+ }
+ }
+
private void updateCryptoUserInfo(int userId) {
if (userId != UserHandle.USER_SYSTEM) {
return;
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d9428c5..0852f82 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -349,6 +349,7 @@
"android_view_DisplayListCanvas.cpp",
"android_view_RenderNode.cpp",
"android_util_PathParser.cpp",
+ "android_util_SeempLog.cpp",
"android/graphics/AnimatedImageDrawable.cpp",
"android/graphics/Bitmap.cpp",
@@ -382,6 +383,7 @@
"android/graphics/fonts/FontFamily.cpp",
"android/graphics/text/LineBreaker.cpp",
"android/graphics/text/MeasuredText.cpp",
+ "com_android_internal_app_ActivityTrigger.cpp",
],
local_include_dirs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4f7f18e..a3d56a6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -99,6 +99,7 @@
extern int register_android_media_midi(JNIEnv *env);
namespace android {
+extern int register_android_util_SeempLog(JNIEnv* env);
/*
* JNI-based registration functions. Note these are properly contained in
@@ -186,6 +187,7 @@
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
+extern int register_com_android_internal_app_ActivityTrigger(JNIEnv *env);
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
@@ -1405,6 +1407,7 @@
}
static const RegJNIRec gRegJNI[] = {
+ REG_JNI(register_android_util_SeempLog),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
@@ -1534,6 +1537,7 @@
REG_JNI(register_android_security_Scrypt),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_os_FuseAppLoop),
+ REG_JNI(register_com_android_internal_app_ActivityTrigger),
};
/*
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index bc69735..adc2b10 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -62,6 +62,18 @@
jmethodID rect_constructor;
jmethodID face_constructor;
jmethodID point_constructor;
+ jfieldID face_sm_degree;
+ jfieldID face_sm_score;
+ jfieldID face_blink_detected;
+ jfieldID face_gaze_angle;
+ jfieldID face_updown_dir;
+ jfieldID face_leftright_dir;
+ jfieldID face_roll_dir;
+ jfieldID face_leye_blink;
+ jfieldID face_reye_blink;
+ jfieldID face_left_right_gaze;
+ jfieldID face_top_bottom_gaze;
+ jfieldID face_recognised;
};
static fields_t fields;
@@ -100,6 +112,7 @@
jclass mFaceClass; // strong reference to Face class
jclass mRectClass; // strong reference to Rect class
jclass mPointClass; // strong reference to Point class
+ bool mIsExtendedFace;
Mutex mLock;
/*
@@ -151,8 +164,16 @@
mCameraJClass = (jclass)env->NewGlobalRef(clazz);
mCamera = camera;
- jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
- mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
+ jclass extendedfaceClazz = env->FindClass("com/qualcomm/qti/camera/ExtendedFace");
+ if (NULL != extendedfaceClazz) {
+ mFaceClass = (jclass) env->NewGlobalRef(extendedfaceClazz);
+ mIsExtendedFace = true;
+ } else {
+ env->ExceptionClear();
+ jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
+ mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
+ mIsExtendedFace = false;
+ }
jclass rectClazz = env->FindClass("android/graphics/Rect");
mRectClass = (jclass) env->NewGlobalRef(rectClazz);
@@ -404,7 +425,6 @@
env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]);
env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]);
env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]);
-
env->SetObjectField(face, fields.face_rect, rect);
env->SetIntField(face, fields.face_score, metadata->faces[i].score);
@@ -433,6 +453,21 @@
env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]);
env->SetObjectField(face, fields.face_mouth, mouth);
env->DeleteLocalRef(mouth);
+
+ if (mIsExtendedFace) {
+ env->SetIntField(face, fields.face_sm_degree, metadata->faces[i].smile_degree);
+ env->SetIntField(face, fields.face_sm_score, metadata->faces[i].smile_score);
+ env->SetIntField(face, fields.face_blink_detected, metadata->faces[i].blink_detected);
+ env->SetIntField(face, fields.face_recognised, metadata->faces[i].face_recognised);
+ env->SetIntField(face, fields.face_gaze_angle, metadata->faces[i].gaze_angle);
+ env->SetIntField(face, fields.face_updown_dir, metadata->faces[i].updown_dir);
+ env->SetIntField(face, fields.face_leftright_dir, metadata->faces[i].leftright_dir);
+ env->SetIntField(face, fields.face_roll_dir, metadata->faces[i].roll_dir);
+ env->SetIntField(face, fields.face_leye_blink, metadata->faces[i].leye_blink);
+ env->SetIntField(face, fields.face_reye_blink, metadata->faces[i].reye_blink);
+ env->SetIntField(face, fields.face_left_right_gaze, metadata->faces[i].left_right_gaze);
+ env->SetIntField(face, fields.face_top_bottom_gaze, metadata->faces[i].top_bottom_gaze);
+ }
}
env->DeleteLocalRef(face);
@@ -470,6 +505,56 @@
}
}
+static void android_hardware_Camera_setLongshot(JNIEnv *env, jobject thiz, jboolean enable)
+{
+ ALOGV("setLongshot");
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if ( enable ) {
+ rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_ON, 0, 0);
+ } else {
+ rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_OFF, 0, 0);
+ }
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "enabling longshot mode failed");
+ }
+}
+
+static void android_hardware_Camera_sendHistogramData(JNIEnv *env, jobject thiz)
+ {
+ ALOGV("sendHistogramData" );
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_SEND_DATA, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "send histogram data failed");
+ }
+ }
+ static void android_hardware_Camera_setHistogramMode(JNIEnv *env, jobject thiz, jboolean mode)
+ {
+ ALOGV("setHistogramMode: mode:%d", (int)mode);
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if(mode == true)
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_ON, 0, 0);
+ else
+ rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_OFF, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "set histogram mode failed");
+ }
+ }
void JNICameraContext::addCallbackBuffer(
JNIEnv *env, jbyteArray cbb, int msgType)
{
@@ -793,7 +878,25 @@
context->setCallbackMode(env, installed, manualBuffer);
}
-static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, jint msgType) {
+static void android_hardware_Camera_setMetadataCb(JNIEnv *env, jobject thiz, jboolean mode)
+{
+ ALOGV("setMetadataCb: mode:%d", (int)mode);
+ JNICameraContext* context;
+ status_t rc;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ if(mode == true)
+ rc = camera->sendCommand(CAMERA_CMD_METADATA_ON, 0, 0);
+ else
+ rc = camera->sendCommand(CAMERA_CMD_METADATA_OFF, 0, 0);
+
+ if (rc != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "set metadata mode failed");
+ }
+}
+
+static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) {
ALOGV("addCallbackBuffer: 0x%x", msgType);
JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));
@@ -1061,7 +1164,7 @@
//-------------------------------------------------
static const JNINativeMethod camMethods[] = {
- { "getNumberOfCameras",
+ { "_getNumberOfCameras",
"()I",
(void *)android_hardware_Camera_getNumberOfCameras },
{ "_getCameraInfo",
@@ -1106,6 +1209,18 @@
{ "native_takePicture",
"(I)V",
(void *)android_hardware_Camera_takePicture },
+ { "native_setHistogramMode",
+ "(Z)V",
+ (void *)android_hardware_Camera_setHistogramMode },
+ { "native_setMetadataCb",
+ "(Z)V",
+ (void *)android_hardware_Camera_setMetadataCb },
+ { "native_sendHistogramData",
+ "()V",
+ (void *)android_hardware_Camera_sendHistogramData },
+ { "native_setLongshot",
+ "(Z)V",
+ (void *)android_hardware_Camera_setLongshot },
{ "native_setParameters",
"(Ljava/lang/String;)V",
(void *)android_hardware_Camera_setParameters },
@@ -1190,6 +1305,27 @@
{ "android/graphics/Point", "y", "I", &fields.point_y},
};
+ field extendedfacefields_to_find[] = {
+ { "com/qualcomm/qti/camera/ExtendedFace", "rect", "Landroid/graphics/Rect;", &fields.face_rect },
+ { "com/qualcomm/qti/camera/ExtendedFace", "score", "I", &fields.face_score },
+ { "com/qualcomm/qti/camera/ExtendedFace", "id", "I", &fields.face_id },
+ { "com/qualcomm/qti/camera/ExtendedFace", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye },
+ { "com/qualcomm/qti/camera/ExtendedFace", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye },
+ { "com/qualcomm/qti/camera/ExtendedFace", "mouth", "Landroid/graphics/Point;", &fields.face_mouth },
+ { "com/qualcomm/qti/camera/ExtendedFace", "smileDegree", "I", &fields.face_sm_degree },
+ { "com/qualcomm/qti/camera/ExtendedFace", "smileScore", "I", &fields.face_sm_score },
+ { "com/qualcomm/qti/camera/ExtendedFace", "blinkDetected", "I", &fields.face_blink_detected },
+ { "com/qualcomm/qti/camera/ExtendedFace", "faceRecognized", "I", &fields.face_recognised },
+ { "com/qualcomm/qti/camera/ExtendedFace", "gazeAngle", "I", &fields.face_gaze_angle },
+ { "com/qualcomm/qti/camera/ExtendedFace", "updownDir", "I", &fields.face_updown_dir },
+ { "com/qualcomm/qti/camera/ExtendedFace", "leftrightDir", "I", &fields.face_leftright_dir },
+ { "com/qualcomm/qti/camera/ExtendedFace", "rollDir", "I", &fields.face_roll_dir },
+ { "com/qualcomm/qti/camera/ExtendedFace", "leyeBlink", "I", &fields.face_leye_blink },
+ { "com/qualcomm/qti/camera/ExtendedFace", "reyeBlink", "I", &fields.face_reye_blink },
+ { "com/qualcomm/qti/camera/ExtendedFace", "leftrightGaze", "I", &fields.face_left_right_gaze },
+ { "com/qualcomm/qti/camera/ExtendedFace", "topbottomGaze", "I", &fields.face_top_bottom_gaze },
+ };
+
find_fields(env, fields_to_find, NELEM(fields_to_find));
jclass clazz = FindClassOrDie(env, "android/hardware/Camera");
@@ -1209,6 +1345,14 @@
return -1;
}
+ clazz = env->FindClass("com/qualcomm/qti/camera/ExtendedFace");
+ if (NULL != clazz) {
+ fields.face_constructor = env->GetMethodID(clazz, "<init>", "()V");
+ find_fields(env, extendedfacefields_to_find, NELEM(extendedfacefields_to_find));
+ }else {
+ env->ExceptionClear();
+ }
+
// Register native functions
return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 99b5f85..1a9762b 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -39,6 +39,13 @@
#define ENCODING_E_AC3_JOC 18
#define ENCODING_DOLBY_MAT 19
+#define ENCODING_AMR_NB 100
+#define ENCODING_AMR_WB 101
+#define ENCODING_EVRC 102
+#define ENCODING_EVRC_B 103
+#define ENCODING_EVRC_WB 104
+#define ENCODING_EVRC_NW 105
+
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -82,6 +89,20 @@
return AUDIO_FORMAT_AAC_XHE;
case ENCODING_AC4:
return AUDIO_FORMAT_AC4;
+ // case ENCODING_E_AC3_JOC: // FIXME Not defined on the native side yet
+ // return AUDIO_FORMAT_E_AC3_JOC;
+ case ENCODING_AMR_NB:
+ return AUDIO_FORMAT_AMR_NB;
+ case ENCODING_AMR_WB:
+ return AUDIO_FORMAT_AMR_WB;
+ case ENCODING_EVRC:
+ return AUDIO_FORMAT_EVRC;
+ case ENCODING_EVRC_B:
+ return AUDIO_FORMAT_EVRCB;
+ case ENCODING_EVRC_WB:
+ return AUDIO_FORMAT_EVRCWB;
+ case ENCODING_EVRC_NW:
+ return AUDIO_FORMAT_EVRCNW;
case ENCODING_E_AC3_JOC:
return AUDIO_FORMAT_E_AC3_JOC;
case ENCODING_DEFAULT:
@@ -135,6 +156,20 @@
return ENCODING_AAC_XHE;
case AUDIO_FORMAT_AC4:
return ENCODING_AC4;
+ // case AUDIO_FORMAT_E_AC3_JOC: // FIXME Not defined on the native side yet
+ // return ENCODING_E_AC3_JOC;
+ case AUDIO_FORMAT_AMR_NB:
+ return ENCODING_AMR_NB;
+ case AUDIO_FORMAT_AMR_WB:
+ return ENCODING_AMR_WB;
+ case AUDIO_FORMAT_EVRC:
+ return ENCODING_EVRC;
+ case AUDIO_FORMAT_EVRCB:
+ return ENCODING_EVRC_B;
+ case AUDIO_FORMAT_EVRCWB:
+ return ENCODING_EVRC_WB;
+ case AUDIO_FORMAT_EVRCNW:
+ return ENCODING_EVRC_NW;
case AUDIO_FORMAT_E_AC3_JOC:
return ENCODING_E_AC3_JOC;
case AUDIO_FORMAT_MAT:
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 49c5cad..9267c9a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -22,6 +22,8 @@
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <cutils/sched_policy.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <meminfo/procmeminfo.h>
@@ -76,6 +78,8 @@
// this size and retry until the whole file fits.
static constexpr ssize_t kProcReadMinHeapBufferSize = 4096;
+static int kCgroupFollowForDex2oatOnly = -1;
+
#if GUARD_THREAD_PRIORITY
Mutex gKeyCreateMutex;
static pthread_key_t gBgKey = -1;
@@ -207,11 +211,19 @@
return;
}
+ SchedPolicy sp = (SchedPolicy) grp;
int res = SetTaskProfiles(tid, {get_sched_policy_name((SchedPolicy)grp)}, true) ? 0 : -1;
if (res != NO_ERROR) {
signalExceptionForGroupError(env, -res, tid);
}
+
+ if ((grp == SP_AUDIO_APP) || (grp == SP_AUDIO_SYS)) {
+ res = set_cpuset_policy(tid, sp);
+ if (res != NO_ERROR) {
+ signalExceptionForGroupError(env, -res, tid);
+ }
+ }
}
void android_os_Process_setThreadGroupAndCpuset(JNIEnv* env, jobject clazz, int tid, jint grp)
@@ -327,6 +339,75 @@
closedir(d);
}
+void android_os_Process_setCgroupProcsProcessGroup(JNIEnv* env, jobject clazz, int uid, int pid, jint grp)
+{
+ int fd;
+ char path[255];
+ if ((grp == SP_FOREGROUND) || (grp > SP_MAX)) {
+ signalExceptionForGroupError(env, EINVAL, pid);
+ return;
+ }
+
+ //read property only for the first time
+ if (kCgroupFollowForDex2oatOnly==-1) {
+ char prop[PROPERTY_VALUE_MAX];
+ kCgroupFollowForDex2oatOnly=0;
+ if (property_get("ro.vendor.qti.cgroup_follow.dex2oat_only", prop, NULL) != 0) {
+ if (strcmp(prop, "true")==0) {
+ kCgroupFollowForDex2oatOnly=1;
+ }
+ }
+ }
+ //set process group for current process
+ android_os_Process_setProcessGroup(env, clazz, pid, grp);
+
+ //find processes in the same cgroup.procs of current uid and pid
+ snprintf(path, sizeof(path), "/acct/uid_%d/pid_%d/cgroup.procs", uid, pid);
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ char buffer[255];
+ char ch;
+ int numRead;
+ size_t len=0;
+ for (;;) {
+ numRead=read(fd, &ch, 1);
+ if (numRead <= 0) break;
+ if (ch != '\n') {
+ buffer[len++]=ch;
+ } else {
+ int temp_pid = atoi(buffer);
+ len=0;
+ if (temp_pid == pid) continue;
+ if (kCgroupFollowForDex2oatOnly==1) {
+ //check if cmdline of temp_pid is starts with /system/bin/dex2oat
+ char cmdline[32];
+ snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", temp_pid);
+ int cmdline_fd = open(cmdline, O_RDONLY);
+ if (cmdline_fd >= 0) {
+ const char *dex2oat_cmd_str = "/system/bin/dex2oat";
+ size_t dex2oat_cmd_len = strlen(dex2oat_cmd_str);
+ size_t read_size = read(cmdline_fd, buffer, dex2oat_cmd_len);
+ close(cmdline_fd);
+ if (read_size<dex2oat_cmd_len) {
+ continue;
+ }
+ buffer[read_size]='\0';
+ if (strcmp(buffer, dex2oat_cmd_str)!=0) {
+ continue;
+ }
+ } else {
+ //ALOGE("read %s failed", cmdline);
+ continue;
+ }
+ }
+ //set cgroup of temp_pid follow pid
+ android_os_Process_setProcessGroup(env, clazz, temp_pid, grp);
+ }
+ }
+ close(fd);
+ }
+}
+
jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
{
SchedPolicy sp;
@@ -384,8 +465,21 @@
}
break;
case SP_FOREGROUND:
+ if (!CgroupGetAttributePath("HighCapacityCPUs", &filename)) {
+ return;
+ }
+ break;
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
+ if (!CgroupGetAttributePath("AudioAppCapacityCPUs", &filename)) {
+ return;
+ }
+ if (access(filename.c_str(), F_OK) != 0) {
+ if (!CgroupGetAttributePath("HighCapacityCPUs", &filename)) {
+ return;
+ }
+ }
+ break;
case SP_RT_APP:
if (!CgroupGetAttributePath("HighCapacityCPUs", &filename)) {
return;
@@ -1283,6 +1377,7 @@
{"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
{"setThreadGroupAndCpuset", "(II)V", (void*)android_os_Process_setThreadGroupAndCpuset},
{"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
+ {"setCgroupProcsProcessGroup", "(III)V", (void*)android_os_Process_setCgroupProcsProcessGroup},
{"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
{"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
{"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
diff --git a/core/jni/android_util_SeempLog.cpp b/core/jni/android_util_SeempLog.cpp
new file mode 100644
index 0000000..e48d114
--- /dev/null
+++ b/core/jni/android_util_SeempLog.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2007-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <assert.h>
+#include <cutils/properties.h>
+#include <utils/String8.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+#include <utils/Log.h>
+
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#define LOG_BUF_SIZE 1024
+#define SEEMP_SOCK_NAME "/dev/socket/seempdw"
+#define ZYGOTE_PARENT_PID 1
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+static int __write_to_log_init(struct iovec *vec, size_t nr);
+static int (*write_to_log)(struct iovec *vec, size_t nr) = __write_to_log_init;
+static int logd_fd = -1;
+
+/* give up, resources too limited */
+static int __write_to_log_null(struct iovec *vec __unused,
+ size_t nr __unused)
+{
+ return -1;
+}
+
+/* log_init_lock assumed */
+static int __write_to_log_initialize()
+{
+ int i, ret = 0;
+ if (logd_fd >= 0) {
+ i = logd_fd;
+ logd_fd = -1;
+ close(i);
+ }
+
+ i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (i < 0) {
+ ret = -errno;
+ write_to_log = __write_to_log_null;
+ } else if (fcntl(i, F_SETFL, O_NONBLOCK) < 0) {
+ ret = -errno;
+ close(i);
+ i = -1;
+ write_to_log = __write_to_log_null;
+ } else {
+ struct sockaddr_un un;
+ memset(&un, 0, sizeof(struct sockaddr_un));
+ un.sun_family = AF_UNIX;
+ strlcpy(un.sun_path, SEEMP_SOCK_NAME, sizeof(un.sun_path));
+ if (connect(i, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) < 0) {
+ ret = -errno;
+ close(i);
+ i = -1;
+ }
+ }
+ logd_fd = i;
+ return ret;
+}
+
+static int __write_to_log_socket(struct iovec *vec, size_t nr)
+{
+ ssize_t ret;
+ if (logd_fd < 0) {
+ return -EBADF;
+ }
+
+ /*
+ * The write below could be lost, but will never block.
+ *
+ * ENOTCONN occurs if logd dies.
+ * EAGAIN occurs if logd is overloaded.
+ */
+ ret = writev(logd_fd, vec, nr);
+ if (ret < 0) {
+ ret = -errno;
+ if (ret == -ENOTCONN) {
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = writev(logd_fd, vec, nr);
+ if (ret < 0) {
+ ret = -errno;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int __write_to_log_init(struct iovec *vec, size_t nr)
+{
+ if (write_to_log == __write_to_log_init) {
+
+ if (getppid() == ZYGOTE_PARENT_PID) {
+ return 0;
+ }
+
+ int ret;
+
+ ret = __write_to_log_initialize();
+ if (ret < 0) {
+ return ret;
+ }
+
+ write_to_log = __write_to_log_socket;
+ }
+ return write_to_log(vec, nr);
+}
+
+int __android_seemp_socket_write(int len, const char *msg)
+{
+ struct iovec vec;
+ vec.iov_base = (void *) msg;
+ vec.iov_len = len;
+
+ return write_to_log(&vec, 1);
+}
+
+namespace android {
+
+/*
+ * In class android.util.Log:
+ * public static native int println_native(int buffer, int priority, String tag, String msg)
+ */
+static jint android_util_SeempLog_println_native(JNIEnv* env, jobject clazz,
+ jint api, jstring msgObj)
+{
+ if (msgObj == NULL) {
+ jniThrowNullPointerException(env, "seemp_println needs a message");
+ return -1;
+ }
+
+ int apiId = (int)api;
+ int apiIdLen = sizeof(apiId);
+ int utf8MsgLen = env->GetStringUTFLength(msgObj);
+ int len = apiIdLen + 1 + utf8MsgLen + 1;
+ char *msg = (char*)malloc(len);
+ if ( NULL == msg )
+ {
+ return -1;
+ }
+ char *params = msg + apiIdLen + 1; // api_id + encoding byte + params
+
+ *((int*)msg) = apiId; // copy api id
+ // // skip encoding byte
+ env->GetStringUTFRegion(msgObj, 0, env->GetStringLength(msgObj), params); // copy message
+ msg[len - 1] = 0; // copy terminating zero
+
+ int res = __android_seemp_socket_write(len, msg); // send message
+
+ free(msg);
+
+ return res;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "seemp_println_native", "(ILjava/lang/String;)I",
+ (void*) android_util_SeempLog_println_native },
+};
+
+int register_android_util_SeempLog(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/util/SeempLog");
+ if (clazz == NULL) {
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/util/SeempLog", gMethods,
+ NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 59dab0c8..d8ca19e 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -45,6 +45,7 @@
jmethodID dispatchInputEvent;
jmethodID dispatchBatchedInputEventPending;
+ jmethodID dispatchMotionEventInfo;
} gInputEventReceiverClassInfo;
@@ -76,6 +77,8 @@
bool mBatchedInputEventPending;
int mFdEvents;
Vector<Finish> mFinishQueue;
+ int mLastMotionEventType = -1;
+ int mLastTouchMoveNum = -1;
void setFdEvents(int events);
@@ -234,9 +237,33 @@
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
+ int motionEventType = -1;
+ int touchMoveNum = -1;
+ bool flag = false;
+
InputEvent* inputEvent;
status_t status = mInputConsumer.consume(&mInputEventFactory,
- consumeBatches, frameTime, &seq, &inputEvent);
+ consumeBatches, frameTime, &seq, &inputEvent,
+ &motionEventType, &touchMoveNum, &flag);
+
+ if (!receiverObj.get()) {
+ receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
+ if (!receiverObj.get()) {
+ ALOGW("channel '%s' ~ Receiver object was finalized "
+ "without being disposed.", getInputChannelName().c_str());
+ return DEAD_OBJECT;
+ }
+ }
+
+ if (flag && ((mLastMotionEventType != motionEventType) ||
+ (mLastTouchMoveNum != touchMoveNum))) {
+ env->CallVoidMethod(receiverObj.get(),
+ gInputEventReceiverClassInfo.dispatchMotionEventInfo, motionEventType, touchMoveNum);
+ mLastMotionEventType = motionEventType;
+ mLastTouchMoveNum = touchMoveNum;
+ flag = false;
+ }
+
if (status) {
if (status == WOULD_BLOCK) {
if (!skipCallbacks && !mBatchedInputEventPending
@@ -423,7 +450,8 @@
"dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending = GetMethodIDOrDie(env,
gInputEventReceiverClassInfo.clazz, "dispatchBatchedInputEventPending", "()V");
-
+ gInputEventReceiverClassInfo.dispatchMotionEventInfo = GetMethodIDOrDie(env,
+ gInputEventReceiverClassInfo.clazz, "dispatchMotionEventInfo", "(II)V");
return res;
}
diff --git a/core/jni/com_android_internal_app_ActivityTrigger.cpp b/core/jni/com_android_internal_app_ActivityTrigger.cpp
new file mode 100644
index 0000000..9d22f69
--- /dev/null
+++ b/core/jni/com_android_internal_app_ActivityTrigger.cpp
@@ -0,0 +1,256 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_TAG "ActTriggerJNI"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <dlfcn.h>
+#include <limits.h>
+#include <string.h>
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+
+namespace android
+{
+
+// ----------------------------------------------------------------------------
+/*
+ * Stuct containing handle to dynamically loaded lib as well as function
+ * pointers to key interfaces.
+ */
+typedef struct dlLibHandler {
+ void *dlhandle;
+ void (*startActivity)(const char *, int *);
+ void (*startApp)(const char *, int *);
+ void (*resumeActivity)(const char *);
+ void (*pauseActivity)(const char *);
+ void (*stopActivity)(const char *);
+ void (*init)(void);
+ void (*deinit)(void);
+ void (*miscActivity)(int, const char *, int, int, float *);
+ const char *dlname;
+}dlLibHandler;
+
+/*
+ * Init for activity trigger library
+ */
+static dlLibHandler mDlLibHandler = {
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "libqti-at.so"
+};
+
+// ----------------------------------------------------------------------------
+
+static void
+com_android_internal_app_ActivityTrigger_native_at_init()
+{
+ bool errored = false;
+
+ mDlLibHandler.dlhandle = dlopen(mDlLibHandler.dlname, RTLD_NOW | RTLD_LOCAL);
+ if (mDlLibHandler.dlhandle == NULL) {
+ return;
+ }
+
+ *(void **) (&mDlLibHandler.startActivity) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_start");
+ if (mDlLibHandler.startActivity == NULL) {
+ errored = true;
+ }
+
+ *(void **) (&mDlLibHandler.startApp) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_qspm_start");
+
+ if (!errored) {
+ *(void **) (&mDlLibHandler.resumeActivity) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_resume");
+ if (mDlLibHandler.resumeActivity == NULL) {
+ errored = true;
+ }
+ }
+ if (!errored) {
+ *(void **) (&mDlLibHandler.pauseActivity) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_pause");
+ if (mDlLibHandler.pauseActivity == NULL) {
+ errored = true;
+ }
+ }
+ if (!errored) {
+ *(void **) (&mDlLibHandler.stopActivity) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_stop");
+ if (mDlLibHandler.stopActivity == NULL) {
+ errored = true;
+ }
+ }
+ if (!errored) {
+ *(void **) (&mDlLibHandler.init) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_init");
+ if (mDlLibHandler.init == NULL) {
+ errored = true;
+ }
+ }
+ if (!errored) {
+ *(void **) (&mDlLibHandler.miscActivity) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_misc");
+ if (mDlLibHandler.miscActivity == NULL) {
+ errored = true;
+ }
+ }
+ if (errored) {
+ mDlLibHandler.startActivity = NULL;
+ mDlLibHandler.startApp = NULL;
+ mDlLibHandler.resumeActivity = NULL;
+ mDlLibHandler.pauseActivity = NULL;
+ mDlLibHandler.stopActivity = NULL;
+ mDlLibHandler.miscActivity = NULL;
+ if (mDlLibHandler.dlhandle) {
+ dlclose(mDlLibHandler.dlhandle);
+ mDlLibHandler.dlhandle = NULL;
+ }
+ } else {
+ (*mDlLibHandler.init)();
+ }
+}
+
+static void
+com_android_internal_app_ActivityTrigger_native_at_deinit(JNIEnv *env, jobject clazz)
+{
+ if (mDlLibHandler.dlhandle) {
+ mDlLibHandler.startActivity = NULL;
+ mDlLibHandler.startApp = NULL;
+ mDlLibHandler.resumeActivity = NULL;
+ mDlLibHandler.pauseActivity = NULL;
+ mDlLibHandler.stopActivity = NULL;
+ mDlLibHandler.miscActivity = NULL;
+
+ *(void **) (&mDlLibHandler.deinit) = dlsym(mDlLibHandler.dlhandle, "activity_trigger_deinit");
+ if (mDlLibHandler.deinit) {
+ (*mDlLibHandler.deinit)();
+ }
+
+ dlclose(mDlLibHandler.dlhandle);
+ mDlLibHandler.dlhandle = NULL;
+ }
+}
+
+static jint
+com_android_internal_app_ActivityTrigger_native_at_startActivity(JNIEnv *env, jobject clazz, jstring activity, jint flags)
+{
+ int activiyFlags = flags;
+ if(mDlLibHandler.startActivity && activity) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (actStr) {
+ (*mDlLibHandler.startActivity)(actStr, &activiyFlags);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+ return activiyFlags;
+}
+
+static jint
+com_android_internal_app_ActivityTrigger_native_at_startApp(JNIEnv *env, jobject clazz, jstring activity, jint flags)
+{
+ int activiyFlags = flags;
+ if(mDlLibHandler.startApp && activity) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (actStr) {
+ (*mDlLibHandler.startApp)(actStr, &activiyFlags);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+ return activiyFlags;
+}
+
+static void
+com_android_internal_app_ActivityTrigger_native_at_resumeActivity(JNIEnv *env, jobject clazz, jstring activity)
+{
+ if(mDlLibHandler.resumeActivity && activity) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (actStr) {
+ (*mDlLibHandler.resumeActivity)(actStr);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+}
+
+static void
+com_android_internal_app_ActivityTrigger_native_at_pauseActivity(JNIEnv *env, jobject clazz, jstring activity)
+{
+ if(mDlLibHandler.pauseActivity && activity) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (NULL != actStr) {
+ (*mDlLibHandler.pauseActivity)(actStr);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+}
+
+static void
+com_android_internal_app_ActivityTrigger_native_at_stopActivity(JNIEnv *env, jobject clazz, jstring activity)
+{
+ if(mDlLibHandler.stopActivity && activity) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (NULL != actStr) {
+ (*mDlLibHandler.stopActivity)(actStr);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+}
+
+static jfloat
+com_android_internal_app_ActivityTrigger_native_at_miscActivity(JNIEnv *env, jobject clazz, jint func, jstring activity, jint type, jint flag)
+{
+ float scaleValue = -1.0f;
+ if (mDlLibHandler.miscActivity && activity && func) {
+ const char *actStr = env->GetStringUTFChars(activity, NULL);
+ if (actStr) {
+ (*mDlLibHandler.miscActivity)(func, actStr, type, flag, &scaleValue);
+ env->ReleaseStringUTFChars(activity, actStr);
+ }
+ }
+ return scaleValue;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"native_at_startActivity", "(Ljava/lang/String;I)I", (void *)com_android_internal_app_ActivityTrigger_native_at_startActivity},
+ {"native_at_startApp", "(Ljava/lang/String;I)I", (void *)com_android_internal_app_ActivityTrigger_native_at_startApp},
+ {"native_at_resumeActivity", "(Ljava/lang/String;)V", (void *)com_android_internal_app_ActivityTrigger_native_at_resumeActivity},
+ {"native_at_pauseActivity", "(Ljava/lang/String;)V", (void *)com_android_internal_app_ActivityTrigger_native_at_pauseActivity},
+ {"native_at_stopActivity", "(Ljava/lang/String;)V", (void *)com_android_internal_app_ActivityTrigger_native_at_stopActivity},
+ {"native_at_deinit", "()V", (void *)com_android_internal_app_ActivityTrigger_native_at_deinit},
+ {"native_at_miscActivity", "(ILjava/lang/String;II)F", (void *)com_android_internal_app_ActivityTrigger_native_at_miscActivity},
+};
+
+int register_com_android_internal_app_ActivityTrigger(JNIEnv *env)
+{
+ com_android_internal_app_ActivityTrigger_native_at_init();
+
+ return AndroidRuntime::registerNativeMethods(env,
+ "com/android/internal/app/ActivityTrigger", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3516dce..4a76654 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -76,6 +76,8 @@
#include <bionic/malloc.h>
#include <cutils/fs.h>
#include <cutils/multiuser.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
@@ -517,7 +519,14 @@
if (getrlimit(RLIMIT_CORE, &rl) == -1) {
ALOGE("getrlimit(RLIMIT_CORE) failed");
} else {
- rl.rlim_cur = 0;
+ char prop_value[PROPERTY_VALUE_MAX];
+ property_get("persist.debug.trace", prop_value, "0");
+ if (prop_value[0] == '1') {
+ ALOGI("setting RLIM to infinity");
+ rl.rlim_cur = RLIM_INFINITY;
+ } else {
+ rl.rlim_cur = 0;
+ }
if (setrlimit(RLIMIT_CORE, &rl) == -1) {
ALOGE("setrlimit(RLIMIT_CORE) failed");
}
@@ -1222,6 +1231,7 @@
capabilities |= (1LL << CAP_NET_RAW);
capabilities |= (1LL << CAP_NET_BIND_SERVICE);
capabilities |= (1LL << CAP_SYS_NICE);
+ capabilities |= (1LL << CAP_NET_ADMIN);
}
if (multiuser_get_app_id(uid) == AID_NETWORK_STACK) {
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index f7d4b3f..920d0f6 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -701,6 +701,8 @@
optional SettingProto server = 1;
// Timeout in milliseconds to wait for NTP server.
optional SettingProto timeout_ms = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Secondary NTP server.
+ optional SettingProto server_2 = 3;
}
optional Ntp ntp = 84;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c365aae..0304f3f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -49,6 +49,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
<protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
+ <protected-broadcast android:name="com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION" />
<protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
@@ -158,8 +159,10 @@
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
<protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.TWS_PLUS_DEVICE_PAIR" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
+ <protected-broadcast android:name="org.codeaurora.intent.bluetooth.action.REMOTE_ISSUE_OCCURRED" />
<protected-broadcast
android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
@@ -171,6 +174,8 @@
<protected-broadcast
android:name="android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.headset.action.HF_TWSP_BATTERY_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
@@ -351,7 +356,27 @@
<protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_PREFERENCES" />
<protected-broadcast android:name="com.android.server.wifi.wakeup.OPEN_WIFI_SETTINGS" />
<protected-broadcast android:name="com.android.server.wifi.wakeup.TURN_OFF_WIFI_WAKE" />
+
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.WIGIG_CREDENTIAL_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.WIGIG_STATE_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.WIGIG_AP_STATE_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.supplicant.CONNECTION_CHANGE" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.STATE_CHANGE" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.CONFIGURED_NETWORKS_CHANGE" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.SCAN_RESULTS" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.LINK_CONFIGURATION_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.WIGIG_RATE_UPGRADE_STATE_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.wigig.RSSI_CHANGED" />
+ <protected-broadcast android:name="wigig_scan_available" />
+ <protected-broadcast android:name="android.net.wigig.p2p.STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wigig.p2p.CONNECTION_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wigig.p2p.PEERS_CHANGED" />
+ <protected-broadcast android:name="android.net.wigig.p2p.DISCOVERY_STATE_CHANGE" />
+ <protected-broadcast android:name="android.net.wigig.p2p.THIS_DEVICE_CHANGED" />
+ <protected-broadcast android:name="android.net.wigig.p2p.PERSISTENT_GROUPS_CHANGED" />
+
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.net.wifi.WIFI_DATA_STALL" />
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
@@ -376,6 +401,9 @@
<protected-broadcast android:name="android.net.wifi.p2p.PEERS_CHANGED" />
<protected-broadcast android:name="android.net.wifi.p2p.CONNECTION_STATE_CHANGE" />
<protected-broadcast android:name="android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.net.wifi.DPP_EVENT" />
+ <protected-broadcast android:name="android.net.wifi.COUNTRY_CODE_CHANGED" />
+ <protected-broadcast android:name="com.qualcomm.qti.net.wifi.WIFI_DISCONNECT_IN_PROGRESS" />
<protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
<protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
<protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
@@ -566,6 +594,11 @@
<protected-broadcast android:name="android.bluetooth.input.profile.action.HANDSHAKE" />
<protected-broadcast android:name="android.bluetooth.input.profile.action.REPORT" />
+ <protected-broadcast android:name="android.bluetooth.bat.profile.action.BA_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.bat.profile.action.BA_ENC_KEY_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.bat.profile.action.BA_DIV_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.bat.profile.action.BA_STR_ID_CHANGED" />
+
<protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
<protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
@@ -1459,6 +1492,11 @@
<permission android:name="android.permission.MODIFY_CELL_BROADCASTS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to authorize outgoing SMS messages.
+ @hide -->
+ <permission android:name="com.qti.permission.AUTHORIZE_OUTGOING_SMS"
+ android:protectionLevel="signature" />
+
<!-- =============================================================== -->
<!-- Permissions for setting the device alarm -->
<!-- =============================================================== -->
diff --git a/core/res/res/drawable/ic_wifi_4_signal_0.xml b/core/res/res/drawable/ic_wifi_4_signal_0.xml
new file mode 100644
index 0000000..bf07712
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_4_signal_0.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M 12,2.001359 C 7.2499999,2.001359 2.9699999,4.079946 -1.25e-7,7.389946 L 12,21.998641 15.048913,18.289401 A 6.2033902,6.4067802 0 0 1 14.192935,16.186142 L 12,18.851901 2.6983696,7.528533 C 5.2683695,5.268533 8.5799999,3.998641 12,3.998641 c 3.42,0 6.73163,1.269892 9.30163,3.529892 l -0.709239,0.86413 a 6.2033902,6.4067802 0 0 1 2.148097,0.529891 L 24,7.389946 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 24.401344,17.117563 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.8716006 h 1.764737 v 5.8844916 h 1.056598 z M 21.838537,15.770508 V 12.79926 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_4_signal_1.xml b/core/res/res/drawable/ic_wifi_4_signal_1.xml
new file mode 100644
index 0000000..619614f
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_4_signal_1.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 24.401344,17.117563 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.8716006 h 1.764737 v 5.8844916 h 1.056598 z M 21.838537,15.770508 V 12.79926 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 13.10054,18.860054 3.79891,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,13.300272 c -3.2,0 -5.2986406,1.799456 -5.4986408,1.899456 l 5.4986408,6.798914 4.043479,-4.997283 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.933424 7.7288137,8.3389834 0 0 1 0.171196,-1.732337 c -0.961558,-0.505425 -2.35688,-1.035326 -4.153535,-1.035326 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_4_signal_2.xml b/core/res/res/drawable/ic_wifi_4_signal_2.xml
new file mode 100644
index 0000000..e6fd9e8
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_4_signal_2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 24.401344,17.117563 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.8716006 h 1.764737 v 5.8844916 h 1.056598 z M 21.838537,15.770508 V 12.79926 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,9.998641 c -4.3999993,0 -7.297826,2.402446 -7.597826,2.702446 l 7.597826,9.297555 4.133152,-5.111414 a 7.7288137,8.3389834 0 0 1 -0.04891,-0.847826 7.7288137,8.3389834 0 0 1 1.377718,-4.744565 C 17.138647,10.644289 15.284639,9.998641 12.998644,9.998641 Z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_4_signal_3.xml b/core/res/res/drawable/ic_wifi_4_signal_3.xml
new file mode 100644
index 0000000..1b2eb8e
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_4_signal_3.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 24.401344,17.117563 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.8716006 h 1.764737 v 5.8844916 h 1.056598 z M 21.838537,15.770508 V 12.79926 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,7.398098 c -5.3000001,0 -8.8997284,3.003804 -9.1997284,3.203804 l 9.1997284,11.39674 4.03125,-4.997283 A 7.7288137,8.3389834 0 0 1 16.968751,16.039402 7.7288137,8.3389834 0 0 1 20.164403,9.30163 C 18.559413,8.406307 16.154773,7.398098 12.998641,7.398098 Z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_4_signal_4.xml b/core/res/res/drawable/ic_wifi_4_signal_4.xml
new file mode 100644
index 0000000..d264adb
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_4_signal_4.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 24.401344,17.117563 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.8716006 h 1.764737 v 5.8844916 h 1.056598 z M 21.838537,15.770508 V 12.79926 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.099185 c -7.3000003,0 -12.0991851,4.002174 -12.59918509,4.402174 L 12.998641,21.998642 16.944293,17.148098 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.978261 7.7288137,8.3389834 0 0 1 7.634511,-8.335597 l 1.084238,-1.332881 c -0.499999,-0.4 -5.303261,-4.402174 -12.603261,-4.402174 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_5_signal_0.xml b/core/res/res/drawable/ic_wifi_5_signal_0.xml
new file mode 100644
index 0000000..dde3ec8
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_5_signal_0.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M 12,2.001359 C 7.2499999,2.001359 2.9699999,4.079946 -1.25e-7,7.389946 L 12,21.998641 15.048913,18.289401 A 6.2033902,6.4067802 0 0 1 14.192935,16.186142 L 12,18.851901 2.6983696,7.528533 C 5.2683695,5.268533 8.5799999,3.998641 12,3.998641 c 3.42,0 6.73163,1.269892 9.30163,3.529892 l -0.709239,0.86413 a 6.2033902,6.4067802 0 0 1 2.148097,0.529891 L 24,7.389946 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.626571,16.969114 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_5_signal_1.xml b/core/res/res/drawable/ic_wifi_5_signal_1.xml
new file mode 100644
index 0000000..5ab3be1
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_5_signal_1.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.626571,16.969114 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 13.10054,18.860054 3.79891,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,13.300272 c -3.2,0 -5.2986406,1.799456 -5.4986408,1.899456 l 5.4986408,6.798914 4.043479,-4.997283 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.933424 7.7288137,8.3389834 0 0 1 0.171196,-1.732337 c -0.961558,-0.505425 -2.35688,-1.035326 -4.153535,-1.035326 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_5_signal_2.xml b/core/res/res/drawable/ic_wifi_5_signal_2.xml
new file mode 100644
index 0000000..31f0922
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_5_signal_2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.626571,16.969114 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,9.998641 c -4.3999993,0 -7.297826,2.402446 -7.597826,2.702446 l 7.597826,9.297555 4.133152,-5.111414 a 7.7288137,8.3389834 0 0 1 -0.04891,-0.847826 7.7288137,8.3389834 0 0 1 1.377718,-4.744565 C 17.138647,10.644289 15.284639,9.998641 12.998644,9.998641 Z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_5_signal_3.xml b/core/res/res/drawable/ic_wifi_5_signal_3.xml
new file mode 100644
index 0000000..706af96
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_5_signal_3.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.626571,16.969114 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,7.398098 c -5.3000001,0 -8.8997284,3.003804 -9.1997284,3.203804 l 9.1997284,11.39674 4.03125,-4.997283 A 7.7288137,8.3389834 0 0 1 16.968751,16.039402 7.7288137,8.3389834 0 0 1 20.164403,9.30163 C 18.559413,8.406307 16.154773,7.398098 12.998641,7.398098 Z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_5_signal_4.xml b/core/res/res/drawable/ic_wifi_5_signal_4.xml
new file mode 100644
index 0000000..6997bbe
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_5_signal_4.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.626571,16.969114 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.099185 c -7.3000003,0 -12.0991851,4.002174 -12.59918509,4.402174 L 12.998641,21.998642 16.944293,17.148098 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.978261 7.7288137,8.3389834 0 0 1 7.634511,-8.335597 l 1.084238,-1.332881 c -0.499999,-0.4 -5.303261,-4.402174 -12.603261,-4.402174 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_6_signal_0.xml b/core/res/res/drawable/ic_wifi_6_signal_0.xml
new file mode 100644
index 0000000..0d24f5b
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_6_signal_0.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M 12,2.001359 C 7.2499999,2.001359 2.9699999,4.079946 -1.25e-7,7.389946 L 12,21.998641 15.048913,18.289401 A 6.2033902,6.4067802 0 0 1 14.192935,16.186142 L 12,18.851901 2.6983696,7.528533 C 5.2683695,5.268533 8.5799999,3.998641 12,3.998641 c 3.42,0 6.73163,1.269892 9.30163,3.529892 l -0.709239,0.86413 a 6.2033902,6.4067802 0 0 1 2.148097,0.529891 L 24,7.389946 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.217756,16.274066 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 Q 18.820372,17.047 18.820372,15.038537 v 0 q 0,-2.207557 0.875601,-3.323047 Q 20.571575,10.6 22.2,10.6 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.014213,11.89994 22.161228,11.89994 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_6_signal_1.xml b/core/res/res/drawable/ic_wifi_6_signal_1.xml
new file mode 100644
index 0000000..6c580ee
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_6_signal_1.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.217756,16.274066 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 Q 18.820372,17.047 18.820372,15.038537 v 0 q 0,-2.207557 0.875601,-3.323047 Q 20.571575,10.6 22.2,10.6 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.014213,11.89994 22.161228,11.89994 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 13.10054,18.860054 3.79891,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 13.100543,13.300272 c -3.2,0 -5.2986406,1.799456 -5.4986408,1.899456 l 5.4986408,6.798914 4.043479,-4.997283 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.933424 7.7288137,8.3389834 0 0 1 0.171196,-1.732337 c -0.961558,-0.505425 -2.35688,-1.035326 -4.153535,-1.035326 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_6_signal_2.xml b/core/res/res/drawable/ic_wifi_6_signal_2.xml
new file mode 100644
index 0000000..345b898
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_6_signal_2.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.217756,16.274066 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 Q 18.820372,17.047 18.820372,15.038537 v 0 q 0,-2.207557 0.875601,-3.323047 Q 20.571575,10.6 22.2,10.6 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.014213,11.89994 22.161228,11.89994 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,9.998641 c -4.3999993,0 -7.297826,2.402446 -7.597826,2.702446 l 7.597826,9.297555 4.133152,-5.111414 a 7.7288137,8.3389834 0 0 1 -0.04891,-0.847826 7.7288137,8.3389834 0 0 1 1.377718,-4.744565 C 17.138647,10.644289 15.284639,9.998641 12.998644,9.998641 Z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_6_signal_3.xml b/core/res/res/drawable/ic_wifi_6_signal_3.xml
new file mode 100644
index 0000000..3eda6ff
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_6_signal_3.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.217756,16.274066 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 Q 18.820372,17.047 18.820372,15.038537 v 0 q 0,-2.207557 0.875601,-3.323047 Q 20.571575,10.6 22.2,10.6 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.014213,11.89994 22.161228,11.89994 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,7.398098 c -5.3000001,0 -8.8997284,3.003804 -9.1997284,3.203804 l 9.1997284,11.39674 4.03125,-4.997283 A 7.7288137,8.3389834 0 0 1 16.968751,16.039402 7.7288137,8.3389834 0 0 1 20.164403,9.30163 C 18.559413,8.406307 16.154773,7.398098 12.998641,7.398098 Z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.0095112 c -4.75,0 -9.029999,2.078587 -12,5.388587 l 12,14.6005438 3.827446,-4.654892 a 7.7288136,8.3389834 0 0 1 -0.04484,-0.835598 7.7288136,8.3389834 0 0 1 0.460598,-2.816576 L 12.998638,18.860054 3.697008,7.5366842 c 2.57,-2.259999 5.88163,-3.529891 9.30163,-3.529891 3.42,0 6.731631,1.269892 9.301631,3.529891 l -1.247282,1.516305 a 7.7288136,8.3389834 0 0 1 3.305705,-0.876359 l 0.639947,-0.778532 c -2.97,-3.31 -7.250001,-5.388587 -12.000001,-5.388587 z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_wifi_6_signal_4.xml b/core/res/res/drawable/ic_wifi_6_signal_4.xml
new file mode 100644
index 0000000..dc9ff4e
--- /dev/null
+++ b/core/res/res/drawable/ic_wifi_6_signal_4.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 25.217756,16.274066 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 Q 18.820372,17.047 18.820372,15.038537 v 0 q 0,-2.207557 0.875601,-3.323047 Q 20.571575,10.6 22.2,10.6 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.014213,11.89994 22.161228,11.89994 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="m 12.998641,2.099185 c -7.3000003,0 -12.0991851,4.002174 -12.59918509,4.402174 L 12.998641,21.998642 16.944293,17.148098 a 7.7288137,8.3389834 0 0 1 -0.06114,-0.978261 7.7288137,8.3389834 0 0 1 7.634511,-8.335597 l 1.084238,-1.332881 c -0.499999,-0.4 -5.303261,-4.402174 -12.603261,-4.402174 z"/>
+</vector>
diff --git a/core/res/res/values-mcc334-mnc020/config.xml b/core/res/res/values-mcc334-mnc020/config.xml
index 0970517..0e12699 100644
--- a/core/res/res/values-mcc334-mnc020/config.xml
+++ b/core/res/res/values-mcc334-mnc020/config.xml
@@ -18,4 +18,12 @@
-->
<resources>
<bool name="config_use_sim_language_file">false</bool>
-</resources>
\ No newline at end of file
+
+ <bool name="config_pdp_retry_for_29_33_55_enabled">true</bool>
+ <integer name="data_retry_delay">45000</integer>
+ <integer name="data_retry_idle_delay">7200000</integer>
+ <string name="data_conn_status_title"></string>
+ <string name="user_authentication_failed">AUTHENTICATION FAILURE -29-.</string>
+ <string name="service_not_subscribed">NOT SUBSCRIBED TO SERVICE -33-.</string>
+ <string name="multi_conn_to_same_pdn_not_allowed">Multiple PDN connections for a given APN not allowed -55-.</string>
+</resources>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index b49fe49..519c20c 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -30,4 +30,6 @@
<p>The main purpose is for OEMs to customize the rendering of the
lockscreen, setting this to true should come with customized drawables. -->
<bool name="use_lock_pattern_drawable">false</bool>
+ <bool name="config_wifi_dual_sap_mode_enabled">false</bool>
+ <bool name="config_wifi_wap3_sap_mode_enabled">false</bool>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eaf93eb..159517c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -754,6 +754,9 @@
<!-- Wifi driver supports IEEE80211AC for softap -->
<bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
+ <!-- Wifi driver supports IEEE80211AX for softap -->
+ <bool translatable="false" name="config_wifi_softap_ieee80211ax_supported">false</bool>
+
<!-- Indicates that local-only hotspot should be brought up at 5GHz. This option is
for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
<bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
@@ -1927,6 +1930,9 @@
-->
</string-array>
+ <!-- Component name of the combo network location provider. -->
+ <string name="config_comboNetworkLocationProvider" translatable="false">com.qualcomm.location</string>
+
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
@@ -2992,6 +2998,9 @@
<!-- Flag indicating which package name can access DeviceConfig table -->
<string name="config_deviceConfiguratorPackageName" translatable="false"></string>
+ <!-- Define optional package verifier name -->
+ <string name="config_optionalPackageVerifierName" translatable="false"></string>
+
<!-- Flag indicating apps will skip sending hold request before merge. In this case
IMS service implementation will do both.i.e.hold followed by merge. -->
<bool name="skipHoldBeforeMerge">true</bool>
@@ -3958,6 +3967,15 @@
<!-- Package name for ManagedProvisioning which is responsible for provisioning work profiles. -->
<string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
+ <!-- The duration (in milliseconds) for the outgoing sms authorization request to timeout.-->
+ <integer name="config_sms_authorization_timeout_ms">0</integer>
+
+ <!-- Enable sms authorization framework-->
+ <bool name="config_sms_authorization_enabled">false</bool>
+
+ <!-- whether to enable primarycard -->
+ <bool name="config_primarycard">false</bool>
+
<!-- Whether or not swipe up gesture's opt-in setting is available on this device -->
<bool name="config_swipe_up_gesture_setting_available">false</bool>
@@ -3993,6 +4011,10 @@
<!-- Whether or not the "SMS app service" feature is enabled -->
<bool name="config_useSmsAppService">true</bool>
+ <!-- List of names that represent dual SoftAp interfaces. -->
+ <string-array translatable="false" name="config_wifi_dual_sap_interfaces">
+ </string-array>
+
<!-- Class name for the InputEvent compatibility processor override.
Empty string means use the default compatibility processor
(android.view.InputEventCompatProcessor). -->
@@ -4361,4 +4383,16 @@
<!-- Whether or not to show the built-in charging animation when the device begins charging
wirelessly. -->
<bool name="config_showBuiltinWirelessChargingAnim">true</bool>
+
+ <!-- pdp data retry for cause 29, 33 and 55-->
+ <bool name="config_pdp_retry_for_29_33_55_enabled">false</bool>
+ <!--pdp data reject retry delay can be configured here -->
+ <integer name="data_retry_delay">-1</integer>
+ <!-- pdp data reject idle timeout delay-->
+ <integer name="data_retry_idle_delay">-1</integer>
+ <!-- pdp data reject dialog string for cause 29, 33 and 55-->
+ <string name="data_conn_status_title"></string>
+ <string name="user_authentication_failed"></string>
+ <string name="service_not_subscribed"></string>
+ <string name="multi_conn_to_same_pdn_not_allowed"></string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8d96c79..5de931a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -360,6 +360,7 @@
<java-symbol type="bool" name="config_wifi_softap_acs_supported" />
<java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" />
<java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" />
+ <java-symbol type="bool" name="config_wifi_softap_ieee80211ax_supported" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
@@ -1424,6 +1425,21 @@
<java-symbol type="drawable" name="ic_wifi_signal_2" />
<java-symbol type="drawable" name="ic_wifi_signal_3" />
<java-symbol type="drawable" name="ic_wifi_signal_4" />
+ <java-symbol type="drawable" name="ic_wifi_4_signal_0" />
+ <java-symbol type="drawable" name="ic_wifi_4_signal_1" />
+ <java-symbol type="drawable" name="ic_wifi_4_signal_2" />
+ <java-symbol type="drawable" name="ic_wifi_4_signal_3" />
+ <java-symbol type="drawable" name="ic_wifi_4_signal_4" />
+ <java-symbol type="drawable" name="ic_wifi_5_signal_0" />
+ <java-symbol type="drawable" name="ic_wifi_5_signal_1" />
+ <java-symbol type="drawable" name="ic_wifi_5_signal_2" />
+ <java-symbol type="drawable" name="ic_wifi_5_signal_3" />
+ <java-symbol type="drawable" name="ic_wifi_5_signal_4" />
+ <java-symbol type="drawable" name="ic_wifi_6_signal_0" />
+ <java-symbol type="drawable" name="ic_wifi_6_signal_1" />
+ <java-symbol type="drawable" name="ic_wifi_6_signal_2" />
+ <java-symbol type="drawable" name="ic_wifi_6_signal_3" />
+ <java-symbol type="drawable" name="ic_wifi_6_signal_4" />
<java-symbol type="drawable" name="ic_signal_wifi_transient_animation" />
<java-symbol type="drawable" name="ic_hotspot_transient_animation" />
<java-symbol type="drawable" name="ic_bluetooth_transient_animation" />
@@ -2132,6 +2148,7 @@
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
+ <java-symbol type="string" name="config_comboNetworkLocationProvider" />
<java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" />
@@ -2253,6 +2270,7 @@
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
+ <java-symbol type="string" name="config_optionalPackageVerifierName" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -3691,7 +3709,11 @@
<java-symbol type="id" name="user_loading" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" />
+ <java-symbol type="integer" name="config_sms_authorization_timeout_ms" />
+ <java-symbol type="bool" name="config_sms_authorization_enabled" />
+
<java-symbol type="string" name="battery_saver_description_with_learn_more" />
+ <java-symbol type="bool" name="config_primarycard" />
<java-symbol type="string" name="confirm_battery_saver" />
<java-symbol type="attr" name="opticalInsetLeft" />
@@ -3703,6 +3725,13 @@
<java-symbol type="drawable" name="ic_arrow_forward" />
<java-symbol type="drawable" name="ic_permission" />
+ <!-- For Dual SoftaAp -->
+ <java-symbol type="array" name="config_wifi_dual_sap_interfaces" />
+ <java-symbol type="bool" name="config_wifi_dual_sap_mode_enabled" />
+
+ <!-- For WPA3 SoftaAp -->
+ <java-symbol type="bool" name="config_wifi_wap3_sap_mode_enabled" />
+
<java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
<java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
<java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
@@ -3876,4 +3905,12 @@
<java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
+ <!-- For Pdn throttle feature -->
+ <java-symbol type="bool" name="config_pdp_retry_for_29_33_55_enabled" />
+ <java-symbol type="integer" name="data_retry_delay" />
+ <java-symbol type="integer" name="data_retry_idle_delay" />
+ <java-symbol type="string" name="data_conn_status_title" />
+ <java-symbol type="string" name="user_authentication_failed" />
+ <java-symbol type="string" name="service_not_subscribed" />
+ <java-symbol type="string" name="multi_conn_to_same_pdn_not_allowed" />
</resources>
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
old mode 100644
new mode 100755
index 7296cfd..67c9e17
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -37,4 +37,8 @@
<!-- Whitelist of bundled applications which all handle URLs to their websites by default -->
<app-link package="com.android.carrierdefaultapp" />
+
+ <!-- Whitelist of what components are permitted to run in the background -->
+ <allow-in-power-save package="com.android.deskclock" />
+
</config>
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 010f92f..8fd0c49 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -542,6 +542,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@Nullable
public Location getLastKnownLocation(@NonNull String provider) {
+ android.util.SeempLog.record(46);
Preconditions.checkArgument(provider != null, "invalid null provider");
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
@@ -679,6 +680,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(
@NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) {
+ android.util.SeempLog.record(64);
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -709,6 +711,7 @@
@NonNull Criteria criteria,
@NonNull LocationListener listener,
@Nullable Looper looper) {
+ android.util.SeempLog.record(64);
Preconditions.checkArgument(criteria != null, "invalid null criteria");
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -735,6 +738,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(@NonNull String provider,
@NonNull PendingIntent pendingIntent) {
+ android.util.SeempLog.record(64);
Preconditions.checkArgument(provider != null, "invalid null provider");
checkPendingIntent(pendingIntent);
@@ -762,6 +766,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestSingleUpdate(@NonNull Criteria criteria,
@NonNull PendingIntent pendingIntent) {
+ android.util.SeempLog.record(64);
Preconditions.checkArgument(criteria != null, "invalid null criteria");
checkPendingIntent(pendingIntent);
@@ -832,6 +837,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -861,6 +867,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull LocationListener listener, @Nullable Looper looper) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -894,6 +901,7 @@
float minDistanceM,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
+ android.util.SeempLog.record(47);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, minTimeMs, minDistanceM, false);
requestLocationUpdates(request, executor, listener);
@@ -919,6 +927,7 @@
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull LocationListener listener,
@Nullable Looper looper) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(criteria != null, "invalid null criteria");
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -952,6 +961,7 @@
@NonNull Criteria criteria,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
+ android.util.SeempLog.record(47);
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
criteria, minTimeMs, minDistanceM, false);
requestLocationUpdates(request, executor, listener);
@@ -982,6 +992,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
@NonNull PendingIntent pendingIntent) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(provider != null, "invalid null provider");
checkPendingIntent(pendingIntent);
@@ -1009,6 +1020,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(long minTimeMs, float minDistanceM,
@NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(criteria != null, "invalid null criteria");
checkPendingIntent(pendingIntent);
@@ -1046,6 +1058,7 @@
@Nullable LocationRequest locationRequest,
@NonNull LocationListener listener,
@Nullable Looper looper) {
+ android.util.SeempLog.record(47);
Handler handler = looper == null ? new Handler() : new Handler(looper);
requestLocationUpdates(locationRequest, new HandlerExecutor(handler), listener);
}
@@ -1074,6 +1087,7 @@
@Nullable LocationRequest locationRequest,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
+ android.util.SeempLog.record(47);
synchronized (mListeners) {
LocationListenerTransport transport = mListeners.get(listener);
if (transport != null) {
@@ -1124,6 +1138,7 @@
public void requestLocationUpdates(
@Nullable LocationRequest locationRequest,
@NonNull PendingIntent pendingIntent) {
+ android.util.SeempLog.record(47);
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
@@ -1371,6 +1386,7 @@
*/
public boolean sendExtraCommand(
@NonNull String provider, @NonNull String command, @Nullable Bundle extras) {
+ android.util.SeempLog.record(48);
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(command != null, "invalid null command");
@@ -1591,6 +1607,7 @@
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
@NonNull PendingIntent intent) {
+ android.util.SeempLog.record(45);
checkPendingIntent(intent);
if (expiration < 0) expiration = Long.MAX_VALUE;
@@ -1826,6 +1843,7 @@
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
+ android.util.SeempLog.record(43);
UnsupportedOperationException ex = new UnsupportedOperationException(
"GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
@@ -1951,6 +1969,7 @@
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+ android.util.SeempLog.record(44);
return false;
}
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index f0787e9..ec3c0aa 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -282,6 +282,31 @@
**/
public static final int ENCODING_DOLBY_MAT = 19;
+ /** Audio data format: AMRNB
+ * @hide
+ * */
+ public static final int ENCODING_AMRNB = 100;
+ /** Audio data format: AMRWB
+ * @hide
+ * */
+ public static final int ENCODING_AMRWB = 101;
+ /** Audio data format: EVRC
+ * @hide
+ * */
+ public static final int ENCODING_EVRC = 102;
+ /** Audio data format: EVRCB
+ * @hide
+ * */
+ public static final int ENCODING_EVRCB = 103;
+ /** Audio data format: EVRCWB
+ * @hide
+ * */
+ public static final int ENCODING_EVRCWB = 104;
+ /** Audio data format: EVRCNW
+ * @hide
+ * */
+ public static final int ENCODING_EVRCNW = 105;
+
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
switch(enc) {
@@ -505,6 +530,11 @@
public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT);
/** @hide */
public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
+ /** @hide */
+ public static final int CHANNEL_IN_5POINT1 = (CHANNEL_IN_LEFT |
+ CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK |
+ CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED);
+
// CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
/** @hide */
@@ -520,6 +550,15 @@
return 2;
case ENCODING_PCM_FLOAT:
return 4;
+ case ENCODING_AMRNB:
+ return 32;
+ case ENCODING_AMRWB:
+ return 61;
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
+ return 23;
case ENCODING_INVALID:
default:
throw new IllegalArgumentException("Bad audio format " + audioFormat);
@@ -546,6 +585,12 @@
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
return true;
@@ -605,6 +650,12 @@
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
return false;
@@ -915,6 +966,12 @@
case ENCODING_AAC_ELD:
case ENCODING_AAC_XHE:
case ENCODING_AC4:
+ case ENCODING_AMRNB:
+ case ENCODING_AMRWB:
+ case ENCODING_EVRC:
+ case ENCODING_EVRCB:
+ case ENCODING_EVRCWB:
+ case ENCODING_EVRCNW:
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
mEncoding = encoding;
@@ -1135,6 +1192,12 @@
ENCODING_AAC_ELD,
ENCODING_AAC_XHE,
ENCODING_AC4,
+ ENCODING_AMRNB,
+ ENCODING_AMRWB,
+ ENCODING_EVRC,
+ ENCODING_EVRCB,
+ ENCODING_EVRCWB,
+ ENCODING_EVRCNW,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT }
)
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f797da7..f82a3ac 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1462,6 +1462,8 @@
*/
public void setSpeakerphoneOn(boolean on){
final IAudioService service = getService();
+ Log.i(TAG, "In setSpeakerphoneOn(), on: " + on + ", calling application: "
+ + mApplicationContext.getOpPackageName());
try {
service.setSpeakerphoneOn(on);
} catch (RemoteException e) {
@@ -1475,6 +1477,8 @@
* @return true if speakerphone is on, false if it's off
*/
public boolean isSpeakerphoneOn() {
+ Log.i(TAG, "In isSpeakerphoneOn(), calling application: "
+ + mApplicationContext.getOpPackageName());
final IAudioService service = getService();
try {
return service.isSpeakerphoneOn();
@@ -1640,8 +1644,12 @@
* @see #startBluetoothSco()
*/
public boolean isBluetoothScoAvailableOffCall() {
- return getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_bluetooth_sco_off_call);
+ boolean retval;
+ retval = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_bluetooth_sco_off_call);
+ Log.i(TAG, "In isBluetoothScoAvailableOffCall(), calling appilication: " +
+ mApplicationContext.getOpPackageName()+", return value: " + retval);
+ return retval;
}
/**
@@ -1691,6 +1699,8 @@
*/
public void startBluetoothSco(){
final IAudioService service = getService();
+ Log.i(TAG, "In startbluetoothSco(), calling application: "
+ + mApplicationContext.getOpPackageName());
try {
service.startBluetoothSco(mICallBack,
getContext().getApplicationInfo().targetSdkVersion);
@@ -1716,6 +1726,8 @@
*/
@UnsupportedAppUsage
public void startBluetoothScoVirtualCall() {
+ Log.i(TAG, "In startBluetoothScoVirtualCall(), calling application: "
+ + mApplicationContext.getOpPackageName());
final IAudioService service = getService();
try {
service.startBluetoothScoVirtualCall(mICallBack);
@@ -1736,6 +1748,8 @@
// Also used for connections started with {@link #startBluetoothScoVirtualCall()}
public void stopBluetoothSco(){
final IAudioService service = getService();
+ Log.i(TAG, "In stopBluetoothSco(), calling application: "
+ + mApplicationContext.getOpPackageName());
try {
service.stopBluetoothSco(mICallBack);
} catch (RemoteException e) {
@@ -1754,6 +1768,8 @@
*/
public void setBluetoothScoOn(boolean on){
final IAudioService service = getService();
+ Log.i(TAG, "In setBluetoothScoOn(), on: " + on + ", calling application: "
+ + mApplicationContext.getOpPackageName());
try {
service.setBluetoothScoOn(on);
} catch (RemoteException e) {
@@ -1769,6 +1785,8 @@
*/
public boolean isBluetoothScoOn() {
final IAudioService service = getService();
+ Log.i(TAG, "In isBluetoothScoOn(), calling application: "
+ + mApplicationContext.getOpPackageName());
try {
return service.isBluetoothScoOn();
} catch (RemoteException e) {
@@ -4299,6 +4317,38 @@
}
}
+ /**
+ * Indicate A2DP source or sink active device change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+ * This operation is asynchronous but its execution will still be sequentially scheduled
+ * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
+ * int, boolean, int)} and
+ * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
+ * @param device Bluetooth device connected/disconnected
+ * @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param profile profile for the A2DP device
+ * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
+ * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
+ * @param a2dpVolume New volume for the connecting device. Does nothing if
+ * disconnecting. Pass value -1 in case you want this field to be ignored
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * @return a delay in ms that the caller should wait before broadcasting
+ * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
+ * {@hide}
+ */
+ public void handleBluetoothA2dpActiveDeviceChange(
+ BluetoothDevice device, int state, int profile,
+ boolean suppressNoisyIntent, int a2dpVolume) {
+ final IAudioService service = getService();
+ try {
+ service.handleBluetoothA2dpActiveDeviceChange(device,
+ state, profile, suppressNoisyIntent, a2dpVolume);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** {@hide} */
public IRingtonePlayer getRingtonePlayer() {
try {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 0254c97..d573d22 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -794,6 +794,12 @@
case AudioFormat.ENCODING_PCM_FLOAT:
case AudioFormat.ENCODING_PCM_16BIT:
case AudioFormat.ENCODING_PCM_8BIT:
+ case AudioFormat.ENCODING_AMRNB:
+ case AudioFormat.ENCODING_AMRWB:
+ case AudioFormat.ENCODING_EVRC:
+ case AudioFormat.ENCODING_EVRCB:
+ case AudioFormat.ENCODING_EVRCWB:
+ case AudioFormat.ENCODING_EVRCNW:
mAudioFormat = audioFormat;
break;
default:
@@ -1035,6 +1041,9 @@
case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
channelCount = 2;
break;
+ case AudioFormat.CHANNEL_IN_5POINT1:
+ channelCount = 6;
+ break;
case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
@@ -1071,6 +1080,7 @@
*/
public void startRecording()
throws IllegalStateException {
+ android.util.SeempLog.record(70);
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("startRecording() called on an "
+ "uninitialized AudioRecord.");
@@ -1094,6 +1104,7 @@
*/
public void startRecording(MediaSyncEvent syncEvent)
throws IllegalStateException {
+ android.util.SeempLog.record(70);
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("startRecording() called on an "
+ "uninitialized AudioRecord.");
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index bb731a8..c2726b1 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -154,6 +154,9 @@
public static final int AUDIO_FORMAT_APTX = 0x20000000;
public static final int AUDIO_FORMAT_APTX_HD = 0x21000000;
public static final int AUDIO_FORMAT_LDAC = 0x23000000;
+ public static final int AUDIO_FORMAT_CELT = 0x26000000;
+ public static final int AUDIO_FORMAT_APTX_ADAPTIVE = 0x27000000;
+ public static final int AUDIO_FORMAT_APTX_TWSP = 0x2A000000;
/**
* Convert audio format enum values to Bluetooth codec values
@@ -165,6 +168,11 @@
case AUDIO_FORMAT_APTX: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX;
case AUDIO_FORMAT_APTX_HD: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD;
case AUDIO_FORMAT_LDAC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
+ case AUDIO_FORMAT_CELT: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_CELT;
+ case AUDIO_FORMAT_APTX_ADAPTIVE:
+ return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE;
+ case AUDIO_FORMAT_APTX_TWSP:
+ return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP;
default: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
}
}
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 963b1d1..82d8be3 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -275,6 +275,23 @@
private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_4KDCI;
+
+ /**
+ * Quality level corresponding to the 8kuhd (7680 x 4320) resolution.
+ * @hide
+ */
+ public static final int QUALITY_8KUHD = 3001;
+
+ /**
+ * Time lapse quality level corresponding to the 8kuhd (7680 x 4320) resolution.
+ * @hide
+ */
+ public static final int QUALITY_TIME_LAPSE_8KUHD = 3002;
+
+ // Start and end of vendor quality list
+ private static final int QUALITY_VENDOR_LIST_START = QUALITY_8KUHD;
+ private static final int QUALITY_VENDOR_LIST_END = QUALITY_TIME_LAPSE_8KUHD;
+
/**
* Default recording duration in seconds before the session is terminated.
* This is useful for applications like MMS has limited file size requirement.
@@ -460,7 +477,9 @@
(quality >= QUALITY_TIME_LAPSE_LIST_START &&
quality <= QUALITY_TIME_LAPSE_LIST_END) ||
(quality >= QUALITY_HIGH_SPEED_LIST_START &&
- quality <= QUALITY_HIGH_SPEED_LIST_END))) {
+ quality <= QUALITY_HIGH_SPEED_LIST_END) ||
+ (quality >= QUALITY_VENDOR_LIST_START &&
+ quality <= QUALITY_VENDOR_LIST_END))) {
String errMessage = "Unsupported quality level: " + quality;
throw new IllegalArgumentException(errMessage);
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fc05610..ea1630d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -182,6 +182,9 @@
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
+ void handleBluetoothA2dpActiveDeviceChange(in BluetoothDevice device,
+ int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
+
@UnsupportedAppUsage
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 09221a37..f4957c6 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -152,6 +152,20 @@
"application/vnd.ms-powerpoint");
addFileType(MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION,
"application/vnd.openxmlformats-officedocument.presentationml.presentation");
+
+ // addFileType(MtpConstants.FORMAT_DIVX, "video/divx");
+ // addFileType(MtpConstants.FORMAT_FLV, "video/flv");
+ // addFileType(MtpConstants.FORMAT_QCP, "audio/qcelp");
+ // addFileType(MtpConstants.FORMAT_AC3, "audio/ac3");
+ // addFileType(MtpConstants.FORMAT_EC3, "audio/eac3");
+ // addFileType(MtpConstants.FORMAT_AIFF, "audio/x-aiff");
+ // addFileType(MtpConstants.FORMAT_APE, "audio/x-ape");
+ // addFileType(MtpConstants.FORMAT_DSD, "audio/x-dsf");
+ // addFileType(MtpConstants.FORMAT_DSD, "audio/x-dff");
+ // addFileType(MtpConstants.FORMAT_DSD, "audio/dsd");
+ // addFileType(MtpConstants.FORMAT_MHAS, "audio/mhas");
+ // addFileType(MtpConstants.FORMAT_MP4, "audio/mhas");
+
}
/** @deprecated file types no longer exist */
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index bf7da23..600bb4e 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -515,6 +515,12 @@
/** Opus data in a Ogg container */
public static final int OGG = 11;
+
+ /** @hide QCP file format */
+ public static final int QCP = 20;
+
+ /** @hide WAVE media file format*/
+ public static final int WAVE = 21;
};
/**
@@ -541,6 +547,14 @@
public static final int VORBIS = 6;
/** Opus audio codec */
public static final int OPUS = 7;
+ /** @hide EVRC audio codec */
+ public static final int EVRC = 10;
+ /** @hide QCELP audio codec */
+ public static final int QCELP = 11;
+ /** @hide Linear PCM audio codec */
+ public static final int LPCM = 12;
+ /** @hide MPEGH audio codec */
+ public static final int MPEGH = 13;
}
/**
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 5bc8092..ad13dd0 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -170,7 +170,9 @@
(quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END) ||
(quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START &&
- quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END));
+ quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END) ||
+ (quality >= CAMCORDER_QUALITY_VENDOR_LIST_START &&
+ quality <= CAMCORDER_QUALITY_VENDOR_LIST_END));
}
static jobject
diff --git a/mime/java-res/vendor.mime.types b/mime/java-res/vendor.mime.types
index afb8f9e..1861909 100644
--- a/mime/java-res/vendor.mime.types
+++ b/mime/java-res/vendor.mime.types
@@ -39,3 +39,11 @@
#
# Add your custom mappings below this line (with no "#" at the start of the line):
+?audio/qcelp qcp
+?audio/ac3 ac3
+?audio/eac3 ec3
+?audio/x-ape ape
+?audio/x-dsf dsf
+?audio/x-dff dff
+?audio/dsd dsd
+?video/divx divx
\ No newline at end of file
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index c627dfb..65e2140 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -50,7 +50,7 @@
*/
public final class ClientOperation implements Operation, BaseStream {
- private static final String TAG = "ClientOperation";
+ private static final String TAG = "ObexClientOperation";
private static final boolean V = ObexHelper.VDBG;
@@ -460,6 +460,7 @@
> mMaxPacketSize) {
int end = 0;
int start = 0;
+ int processedLen = 0;
// split & send the headerArray in multiple packets.
while (end != headerArray.length) {
@@ -486,10 +487,17 @@
byte[] sendHeader = new byte[end - start];
System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
+ processedLen += sendHeader.length;
+ opCode = (processedLen == headerArray.length) ? ObexHelper.OBEX_OPCODE_GET_FINAL
+ : ObexHelper.OBEX_OPCODE_GET;
+ //Set GET FINAL (0x83) for Last Request Header packet as per GOEP2.1
if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput, false)) {
return false;
}
-
+ if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_OK) {
+ Log.i(TAG, "sendRequest return OBEX_HTTP_OK");
+ return true;
+ }
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
return false;
}
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
index 272a920..9aaf7bc 100644
--- a/obex/javax/obex/ClientSession.java
+++ b/obex/javax/obex/ClientSession.java
@@ -47,7 +47,7 @@
*/
public final class ClientSession extends ObexSession {
- private static final String TAG = "ClientSession";
+ private static final String TAG = "ObexClientSession";
private boolean mOpen;
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 478297f..f09d3d3 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -52,7 +52,8 @@
public final class ObexHelper {
private static final String TAG = "ObexHelper";
- public static final boolean VDBG = false;
+ public static final String LOG_TAG = "BluetoothObex";
+ public static final boolean VDBG = Log.isLoggable(LOG_TAG, Log.VERBOSE);
/**
* Defines the basic packet length used by OBEX. Every OBEX packet has the
* same basic format:<BR>
@@ -89,6 +90,8 @@
*/
public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
+ public static final int A2DP_SCO_OBEX_MAX_CLIENT_PACKET_SIZE = 0x2000;
+
public static final int OBEX_OPCODE_FINAL_BIT_MASK = 0x80;
public static final int OBEX_OPCODE_CONNECT = 0x80;
@@ -193,6 +196,7 @@
try {
while (index < headerArray.length) {
headerID = 0xFF & headerArray[index];
+ if (VDBG) Log.v(TAG,"updateHeaderSet headerID = " + headerID);
switch (headerID & (0xC0)) {
/*
@@ -211,9 +215,9 @@
length = ((0xFF & headerArray[index]) << 8) +
(0xFF & headerArray[index + 1]);
index += 2;
- if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
+ if (length < OBEX_BYTE_SEQ_HEADER_LEN) {
Log.e(TAG, "Remote sent an OBEX packet with " +
- "incorrect header length = " + length);
+ "incorrect header length : " + length);
break;
}
length -= OBEX_BYTE_SEQ_HEADER_LEN;
@@ -381,8 +385,9 @@
* Determine if there is a connection ID to send. If there is,
* then it should be the first header in the packet.
*/
+ if (VDBG) Log.v(TAG,"createHeader = " + head);
if ((headImpl.mConnectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) {
-
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.CONNECTION_ID);
out.write((byte)HeaderSet.CONNECTION_ID);
out.write(headImpl.mConnectionID);
}
@@ -390,6 +395,7 @@
// Count Header
intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT);
if (intHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.COUNT);
out.write((byte)HeaderSet.COUNT);
value = ObexHelper.convertToByteArray(intHeader.longValue());
out.write(value);
@@ -401,6 +407,7 @@
// Name Header
stringHeader = (String)headImpl.getHeader(HeaderSet.NAME);
if (stringHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.NAME);
out.write((byte)HeaderSet.NAME);
value = ObexHelper.convertToUnicodeByteArray(stringHeader);
length = value.length + 3;
@@ -421,6 +428,7 @@
// Type Header
stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE);
if (stringHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.TYPE);
out.write((byte)HeaderSet.TYPE);
try {
value = stringHeader.getBytes("ISO8859_1");
@@ -442,6 +450,7 @@
// Length Header
intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH);
if (intHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.LENGTH);
out.write((byte)HeaderSet.LENGTH);
value = ObexHelper.convertToByteArray(intHeader.longValue());
out.write(value);
@@ -453,7 +462,7 @@
// Time ISO Header
dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601);
if (dateHeader != null) {
-
+ if (VDBG) Log.v(TAG," Add dateHeader = " + HeaderSet.TIME_ISO_8601);
/*
* The ISO Header should take the form YYYYMMDDTHHMMSSZ. The
* 'Z' will only be included if it is a UTC time.
@@ -515,6 +524,7 @@
// Time 4 Byte Header
dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE);
if (dateHeader != null) {
+ if (VDBG) Log.v(TAG," Add dateHeader = " + HeaderSet.TIME_4_BYTE);
out.write(HeaderSet.TIME_4_BYTE);
/*
@@ -549,6 +559,7 @@
// Target Header
value = (byte[])headImpl.getHeader(HeaderSet.TARGET);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.TARGET);
out.write((byte)HeaderSet.TARGET);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -577,6 +588,7 @@
// Who Header
value = (byte[])headImpl.getHeader(HeaderSet.WHO);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.WHO);
out.write((byte)HeaderSet.WHO);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -591,6 +603,7 @@
// Connection ID Header
value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER);
if (value != null) {
+ if (VDBG) Log.v(TAG," Add APP PARAM Header = " + HeaderSet.APPLICATION_PARAMETER);
out.write((byte)HeaderSet.APPLICATION_PARAMETER);
length = value.length + 3;
lengthArray[0] = (byte)(255 & (length >> 8));
@@ -629,6 +642,7 @@
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(value);
+ if (VDBG) Log.v(TAG," Add Unicode String value = " + value);
if (nullOut) {
headImpl.setHeader(i + 0x30, null);
}
@@ -643,6 +657,7 @@
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(value);
+ if (VDBG) Log.v(TAG," Add ByteSeq value = " + value);
if (nullOut) {
headImpl.setHeader(i + 0x70, null);
}
@@ -653,6 +668,7 @@
if (byteHeader != null) {
out.write((byte)i + 0xB0);
out.write(byteHeader.byteValue());
+ if (VDBG) Log.v(TAG," Add ByteHeader value = " + byteHeader.byteValue());
if (nullOut) {
headImpl.setHeader(i + 0xB0, null);
}
@@ -663,6 +679,7 @@
if (intHeader != null) {
out.write((byte)i + 0xF0);
out.write(ObexHelper.convertToByteArray(intHeader.longValue()));
+ if (VDBG) Log.v(TAG," Add Int value = " + intHeader.longValue());
if (nullOut) {
headImpl.setHeader(i + 0xF0, null);
}
@@ -677,6 +694,7 @@
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.mAuthChall);
+ if (VDBG) Log.v(TAG," Add mAuthChall value = " + headImpl.mAuthChall);
if (nullOut) {
headImpl.mAuthChall = null;
}
@@ -690,6 +708,7 @@
lengthArray[1] = (byte)(255 & length);
out.write(lengthArray);
out.write(headImpl.mAuthResp);
+ if (VDBG) Log.v(TAG," Add mAuthChall value = " + headImpl.mAuthResp);
if (nullOut) {
headImpl.mAuthResp = null;
}
@@ -705,8 +724,10 @@
// Add the SRM header
byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
if (byteHeader != null) {
+ if (VDBG) Log.v(TAG," Add SRM Header = " + HeaderSet.SINGLE_RESPONSE_MODE);
out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE);
out.write(byteHeader.byteValue());
+ if (VDBG) Log.v(TAG," Add SRM value = " + byteHeader.byteValue());
if (nullOut) {
headImpl.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, null);
}
@@ -715,6 +736,7 @@
// Add the SRM parameter header
byteHeader = (Byte)headImpl.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
if (byteHeader != null) {
+ if (VDBG) Log.v(TAG," Add Header = " + HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
out.write((byte)HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
out.write(byteHeader.byteValue());
if (nullOut) {
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 15ea367..1cc720b 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -57,7 +57,7 @@
*/
public final class ServerOperation implements Operation, BaseStream {
- private static final String TAG = "ServerOperation";
+ private static final String TAG = "ObexServerOperation";
private static final boolean V = ObexHelper.VDBG; // Verbose debugging
@@ -124,6 +124,7 @@
*/
public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
ServerRequestHandler listen) throws IOException {
+ if (V) Log.v(TAG, "ServerOperation");
isAborted = false;
mParent = p;
@@ -340,14 +341,17 @@
*/
public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
throws IOException {
+ if (V) Log.v(TAG, "continueOperation");
if (!mGetOperation) {
if (!finalBitSet) {
if (sendEmpty) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (V) Log.v(TAG, "continueOperation:ServerSet SRM sendEmpty clause");
return true;
} else {
if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
+ if (V) Log.v(TAG, "continueOperation: Server setting SRM");
return true;
} else {
return false;
@@ -357,6 +361,7 @@
return false;
}
} else {
+ if (V) Log.v(TAG, "Get continueOperation ");
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
return true;
}
@@ -405,6 +410,8 @@
bodyLength = mPrivateOutput.size();
orginalBodyLength = bodyLength;
}
+ if(V) Log.v(TAG, "mMaxPcKLen :" + mMaxPacketLength + " headerArryLen :"
+ + headerArray.length);
if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index dbfeefd..a45687f 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -63,6 +63,12 @@
private boolean mClosed;
+ private boolean setMTU = false;
+
+ private boolean updateMtu = false;
+
+ private int updatedMtuSize = 0;
+
/**
* Creates new ServerSession.
* @param trans the connection to the client
@@ -85,6 +91,25 @@
mProcessThread.start();
}
+ public void setMaxPacketSize(int size) {
+ if (V) Log.v(TAG, "setMaxPacketSize" + size);
+ mMaxPacketLength = size;
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketLength;
+ }
+
+ public void reduceMTU(boolean enable) {
+ setMTU = enable;
+ }
+
+ public void updateMTU(int mtuSize) {
+ updateMtu = true;
+ updatedMtuSize = mtuSize;
+ Log.i(TAG,"updateMTU: " + mtuSize);
+ }
+
/**
* Processes requests made to the server and forwards them to the
* appropriate event listener.
@@ -124,6 +149,7 @@
break;
case -1:
+ Log.d(TAG, "Read request returned -1, exiting from loop");
done = true;
break;
@@ -194,6 +220,7 @@
* @throws IOException if an error occurred at the transport layer
*/
private void handlePutRequest(int type) throws IOException {
+ if (V) Log.v(TAG, "handlePutRequest");
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = -1;
@@ -205,10 +232,12 @@
response = validateResponseCode(mListener.onPut(op));
}
if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
+ if (V) Log.v(TAG, "handlePutRequest pre != HTTP_OK sendReply");
op.sendReply(response);
} else if (!op.isAborted) {
// wait for the final bit
while (!op.finalBitSet) {
+ if (V) Log.v(TAG, "handlePutRequest pre looped sendReply");
op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
}
op.sendReply(response);
@@ -240,6 +269,7 @@
* @throws IOException if an error occurred at the transport layer
*/
private void handleGetRequest(int type) throws IOException {
+ if (V) Log.v(TAG, "handleGetRequest");
ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
try {
int response = validateResponseCode(mListener.onGet(op));
@@ -262,6 +292,7 @@
public void sendResponse(int code, byte[] header) throws IOException {
int totalLength = 3;
byte[] data = null;
+ if (V) Log.v(TAG,"sendResponse code " + code + " header : " + header);
OutputStream op = mOutput;
if (op == null) {
return;
@@ -269,6 +300,7 @@
if (header != null) {
totalLength += header.length;
+ if (V) Log.v(TAG, "header != null totalLength = " + totalLength);
data = new byte[totalLength];
data[0] = (byte)code;
data[1] = (byte)(totalLength >> 8);
@@ -558,9 +590,19 @@
+ " MaxLength: " + mMaxPacketLength + " flags: " + flags);
// should we check it?
- if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
+ if (setMTU) {
+ mMaxPacketLength = ObexHelper.A2DP_SCO_OBEX_MAX_CLIENT_PACKET_SIZE;
+ setMTU = false;
+ } else if (updateMtu) {
+ Log.d(TAG, "mMaxPacketLength: " + mMaxPacketLength +
+ ", updatedMtuSize: " + updatedMtuSize);
+ if (mMaxPacketLength > updatedMtuSize)
+ mMaxPacketLength = updatedMtuSize;
+ updateMtu = false;
+ } else if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
}
+ Log.d(TAG,"handleConnectRequest() - Updated MaxPacketLengh: " + mMaxPacketLength);
if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) {
Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8a3e6a0..cc67f55 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1570,6 +1570,10 @@
if (view != null) {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
+ if (mFinishDrawingRunnable != null) {
+ finishDrawingRunnable = mFinishDrawingRunnable;
+ mFinishDrawingRunnable = null;
+ }
view.mRenderer.onDrawFrame(gl);
if (finishDrawingRunnable != null) {
finishDrawingRunnable.run();
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
new file mode 100644
index 0000000..c47231d
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -0,0 +1,1149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
+import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
+import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
+import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_MTU;
+import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
+import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
+import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
+import static android.net.dhcp.DhcpPacket.INADDR_ANY;
+import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
+import static android.net.util.NetworkStackUtils.closeSocketQuietly;
+import static android.net.util.SocketUtils.makePacketSocketAddress;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_IP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_RAW;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BROADCAST;
+import static android.system.OsConstants.SO_RCVBUF;
+import static android.system.OsConstants.SO_REUSEADDR;
+
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
+import android.content.Context;
+import android.net.DhcpResults;
+import android.net.InetAddresses;
+import android.net.TrafficStats;
+import android.net.ip.IpClient;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.DhcpErrorEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.util.InterfaceParams;
+import android.net.util.NetworkStackUtils;
+import android.net.util.SocketUtils;
+import android.os.Message;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.HexDump;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.TrafficStatsConstants;
+import com.android.internal.util.WakeupMessage;
+import com.android.networkstack.R;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * A DHCPv4 client.
+ *
+ * Written to behave similarly to the DhcpStateMachine + dhcpcd 5.5.6 combination used in Android
+ * 5.1 and below, as configured on Nexus 6. The interface is the same as DhcpStateMachine.
+ *
+ * TODO:
+ *
+ * - Exponential backoff when receiving NAKs (not specified by the RFC, but current behaviour).
+ * - Support persisting lease state and support INIT-REBOOT. Android 5.1 does this, but it does not
+ * do so correctly: instead of requesting the lease last obtained on a particular network (e.g., a
+ * given SSID), it requests the last-leased IP address on the same interface, causing a delay if
+ * the server NAKs or a timeout if it doesn't.
+ *
+ * Known differences from current behaviour:
+ *
+ * - Does not request the "static routes" option.
+ * - Does not support BOOTP servers. DHCP has been around since 1993, should be everywhere now.
+ * - Requests the "broadcast" option, but does nothing with it.
+ * - Rejects invalid subnet masks such as 255.255.255.1 (current code treats that as 255.255.255.0).
+ *
+ * @hide
+ */
+public class DhcpClient extends StateMachine {
+
+ private static final String TAG = "DhcpClient";
+ private static final boolean DBG = true;
+ private static final boolean STATE_DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean MSG_DBG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean PACKET_DBG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // Metrics events: must be kept in sync with server-side aggregation code.
+ /** Represents transitions from DhcpInitState to DhcpBoundState */
+ private static final String EVENT_INITIAL_BOUND = "InitialBoundState";
+ /** Represents transitions from and to DhcpBoundState via DhcpRenewingState */
+ private static final String EVENT_RENEWING_BOUND = "RenewingBoundState";
+
+ // Timers and timeouts.
+ private static final int SECONDS = 1000;
+ private static final int FIRST_TIMEOUT_MS = 2 * SECONDS;
+ private static final int MAX_TIMEOUT_MS = 128 * SECONDS;
+
+ // This is not strictly needed, since the client is asynchronous and implements exponential
+ // backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
+ // a blocking operation with a 30-second timeout. We pick 36 seconds so we can send packets at
+ // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
+ private static final int DHCP_TIMEOUT_MS = 36 * SECONDS;
+
+ // DhcpClient uses IpClient's handler.
+ private static final int PUBLIC_BASE = IpClient.DHCPCLIENT_CMD_BASE;
+
+ // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = PUBLIC_BASE + 1;
+ public static final int CMD_STOP_DHCP = PUBLIC_BASE + 2;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = PUBLIC_BASE + 3;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = PUBLIC_BASE + 4;
+ /* Notification from DHCP state machine before quitting */
+ public static final int CMD_ON_QUIT = PUBLIC_BASE + 5;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = PUBLIC_BASE + 6;
+
+ /* Command and event notification to/from IpManager requesting the setting
+ * (or clearing) of an IPv4 LinkAddress.
+ */
+ public static final int CMD_CLEAR_LINKADDRESS = PUBLIC_BASE + 7;
+ public static final int CMD_CONFIGURE_LINKADDRESS = PUBLIC_BASE + 8;
+ public static final int EVENT_LINKADDRESS_CONFIGURED = PUBLIC_BASE + 9;
+
+ /* Command from controller to start DHCP with Rapid commit */
+ public static final int CMD_START_DHCP_RAPID_COMMIT = PUBLIC_BASE + 10;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
+ // Internal messages.
+ private static final int PRIVATE_BASE = IpClient.DHCPCLIENT_CMD_BASE + 100;
+ private static final int CMD_KICK = PRIVATE_BASE + 1;
+ private static final int CMD_RECEIVED_PACKET = PRIVATE_BASE + 2;
+ private static final int CMD_TIMEOUT = PRIVATE_BASE + 3;
+ private static final int CMD_RENEW_DHCP = PRIVATE_BASE + 4;
+ private static final int CMD_REBIND_DHCP = PRIVATE_BASE + 5;
+ private static final int CMD_EXPIRE_DHCP = PRIVATE_BASE + 6;
+
+ // For message logging.
+ private static final Class[] sMessageClasses = { DhcpClient.class };
+ private static final SparseArray<String> sMessageNames =
+ MessageUtils.findMessageNames(sMessageClasses);
+
+ // DHCP parameters that we request.
+ /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
+ DHCP_SUBNET_MASK,
+ DHCP_ROUTER,
+ DHCP_DNS_SERVER,
+ DHCP_DOMAIN_NAME,
+ DHCP_MTU,
+ DHCP_BROADCAST_ADDRESS, // TODO: currently ignored.
+ DHCP_LEASE_TIME,
+ DHCP_RENEWAL_TIME,
+ DHCP_REBINDING_TIME,
+ DHCP_VENDOR_INFO,
+ };
+
+ // DHCP flag that means "yes, we support unicast."
+ private static final boolean DO_UNICAST = false;
+
+ // System services / libraries we use.
+ private final Context mContext;
+ private final Random mRandom;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+
+ // Sockets.
+ // - We use a packet socket to receive, because servers send us packets bound for IP addresses
+ // which we have not yet configured, and the kernel protocol stack drops these.
+ // - We use a UDP socket to send, so the kernel handles ARP and routing for us (DHCP servers can
+ // be off-link as well as on-link).
+ private FileDescriptor mPacketSock;
+ private FileDescriptor mUdpSock;
+ private ReceiveThread mReceiveThread;
+
+ // State variables.
+ private final StateMachine mController;
+ private final WakeupMessage mKickAlarm;
+ private final WakeupMessage mTimeoutAlarm;
+ private final WakeupMessage mRenewAlarm;
+ private final WakeupMessage mRebindAlarm;
+ private final WakeupMessage mExpiryAlarm;
+ private final String mIfaceName;
+
+ private boolean mRegisteredForPreDhcpNotification;
+ private InterfaceParams mIface;
+ // TODO: MacAddress-ify more of this class hierarchy.
+ private byte[] mHwAddr;
+ private SocketAddress mInterfaceBroadcastAddr;
+ private int mTransactionId;
+ private long mTransactionStartMillis;
+ private DhcpResults mDhcpLease;
+ private long mDhcpLeaseExpiry;
+ private DhcpResults mOffer;
+ public boolean mRapidCommit;
+ public boolean mDiscoverSent;
+
+ // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
+ private long mLastInitEnterTime;
+ private long mLastBoundExitTime;
+
+ // States.
+ private State mStoppedState = new StoppedState();
+ private State mDhcpState = new DhcpState();
+ private State mDhcpInitState = new DhcpInitState();
+ private State mDhcpRapidCommitInitState = new DhcpRapidCommitInitState();
+ private State mDhcpSelectingState = new DhcpSelectingState();
+ private State mDhcpRequestingState = new DhcpRequestingState();
+ private State mDhcpHaveLeaseState = new DhcpHaveLeaseState();
+ private State mConfiguringInterfaceState = new ConfiguringInterfaceState();
+ private State mDhcpBoundState = new DhcpBoundState();
+ private State mDhcpRenewingState = new DhcpRenewingState();
+ private State mDhcpRebindingState = new DhcpRebindingState();
+ private State mDhcpInitRebootState = new DhcpInitRebootState();
+ private State mDhcpRebootingState = new DhcpRebootingState();
+ private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
+ private State mRapidCommitWaitBeforeStartState = new WaitBeforeStartState(mDhcpRapidCommitInitState);
+ private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
+
+ private WakeupMessage makeWakeupMessage(String cmdName, int cmd) {
+ cmdName = DhcpClient.class.getSimpleName() + "." + mIfaceName + "." + cmdName;
+ return new WakeupMessage(mContext, getHandler(), cmdName, cmd);
+ }
+
+ // TODO: Take an InterfaceParams instance instead of an interface name String.
+ private DhcpClient(Context context, StateMachine controller, String iface) {
+ super(TAG, controller.getHandler());
+
+ mContext = context;
+ mController = controller;
+ mIfaceName = iface;
+
+ addState(mStoppedState);
+ addState(mDhcpState);
+ addState(mDhcpInitState, mDhcpState);
+ addState(mDhcpRapidCommitInitState, mDhcpState);
+ addState(mWaitBeforeStartState, mDhcpState);
+ addState(mRapidCommitWaitBeforeStartState, mDhcpState);
+ addState(mDhcpSelectingState, mDhcpState);
+ addState(mDhcpRequestingState, mDhcpState);
+ addState(mDhcpHaveLeaseState, mDhcpState);
+ addState(mConfiguringInterfaceState, mDhcpHaveLeaseState);
+ addState(mDhcpBoundState, mDhcpHaveLeaseState);
+ addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState);
+ addState(mDhcpRenewingState, mDhcpHaveLeaseState);
+ addState(mDhcpRebindingState, mDhcpHaveLeaseState);
+ addState(mDhcpInitRebootState, mDhcpState);
+ addState(mDhcpRebootingState, mDhcpState);
+
+ setInitialState(mStoppedState);
+
+ mRandom = new Random();
+
+ // Used to schedule packet retransmissions.
+ mKickAlarm = makeWakeupMessage("KICK", CMD_KICK);
+ // Used to time out PacketRetransmittingStates.
+ mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
+ // Used to schedule DHCP reacquisition.
+ mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
+ mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
+ mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
+ }
+
+ public void registerForPreDhcpNotification() {
+ mRegisteredForPreDhcpNotification = true;
+ }
+
+ public static DhcpClient makeDhcpClient(
+ Context context, StateMachine controller, InterfaceParams ifParams) {
+ DhcpClient client = new DhcpClient(context, controller, ifParams.name);
+ client.mIface = ifParams;
+ client.start();
+ return client;
+ }
+
+ private boolean initInterface() {
+ if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
+ if (mIface == null) {
+ Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName);
+ return false;
+ }
+
+ mHwAddr = mIface.macAddr.toByteArray();
+ mInterfaceBroadcastAddr = makePacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST);
+ return true;
+ }
+
+ private void startNewTransaction() {
+ mTransactionId = mRandom.nextInt();
+ mTransactionStartMillis = SystemClock.elapsedRealtime();
+ }
+
+ private boolean initSockets() {
+ return initPacketSocket() && initUdpSocket();
+ }
+
+ private boolean initPacketSocket() {
+ try {
+ mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
+ SocketAddress addr = makePacketSocketAddress((short) ETH_P_IP, mIface.index);
+ Os.bind(mPacketSock, addr);
+ NetworkStackUtils.attachDhcpFilter(mPacketSock);
+ } catch(SocketException|ErrnoException e) {
+ Log.e(TAG, "Error creating packet socket", e);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean initUdpSocket() {
+ final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+ TrafficStatsConstants.TAG_SYSTEM_DHCP);
+ try {
+ mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName);
+ Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
+ Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
+ Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
+ Os.bind(mUdpSock, IPV4_ADDR_ANY, DhcpPacket.DHCP_CLIENT);
+ } catch(SocketException|ErrnoException e) {
+ Log.e(TAG, "Error creating UDP socket", e);
+ return false;
+ } finally {
+ TrafficStats.setThreadStatsTag(oldTag);
+ }
+ return true;
+ }
+
+ private boolean connectUdpSock(Inet4Address to) {
+ try {
+ Os.connect(mUdpSock, to, DhcpPacket.DHCP_SERVER);
+ return true;
+ } catch (SocketException|ErrnoException e) {
+ Log.e(TAG, "Error connecting UDP socket", e);
+ return false;
+ }
+ }
+
+ private void closeSockets() {
+ closeSocketQuietly(mUdpSock);
+ closeSocketQuietly(mPacketSock);
+ }
+
+ class ReceiveThread extends Thread {
+
+ private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
+ private volatile boolean mStopped = false;
+
+ public void halt() {
+ mStopped = true;
+ closeSockets(); // Interrupts the read() call the thread is blocked in.
+ }
+
+ @Override
+ public void run() {
+ if (DBG) Log.d(TAG, "Receive thread started");
+ while (!mStopped) {
+ int length = 0; // Or compiler can't tell it's initialized if a parse error occurs.
+ try {
+ length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
+ DhcpPacket packet = null;
+ packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
+ if (DBG) Log.d(TAG, "Received packet: " + packet);
+ sendMessage(CMD_RECEIVED_PACKET, packet);
+ } catch (IOException|ErrnoException e) {
+ if (!mStopped) {
+ Log.e(TAG, "Read error", e);
+ logError(DhcpErrorEvent.RECEIVE_ERROR);
+ }
+ } catch (DhcpPacket.ParseException e) {
+ Log.e(TAG, "Can't parse packet: " + e.getMessage());
+ if (PACKET_DBG) {
+ Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
+ }
+ if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
+ int snetTagId = 0x534e4554;
+ String bugId = "31850211";
+ int uid = -1;
+ String data = DhcpPacket.ParseException.class.getName();
+ EventLog.writeEvent(snetTagId, bugId, uid, data);
+ }
+ logError(e.errorCode);
+ }
+ }
+ if (DBG) Log.d(TAG, "Receive thread stopped");
+ }
+ }
+
+ private short getSecs() {
+ return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
+ }
+
+ private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) {
+ try {
+ if (encap == DhcpPacket.ENCAP_L2) {
+ if (DBG) Log.d(TAG, "Broadcasting " + description);
+ Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
+ } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) {
+ if (DBG) Log.d(TAG, "Broadcasting " + description);
+ // We only send L3-encapped broadcasts in DhcpRebindingState,
+ // where we have an IP address and an unconnected UDP socket.
+ //
+ // N.B.: We only need this codepath because DhcpRequestPacket
+ // hardcodes the source IP address to 0.0.0.0. We could reuse
+ // the packet socket if this ever changes.
+ Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
+ } else {
+ // It's safe to call getpeername here, because we only send unicast packets if we
+ // have an IP address, and we connect the UDP socket in DhcpBoundState#enter.
+ if (DBG) Log.d(TAG, String.format("Unicasting %s to %s",
+ description, Os.getpeername(mUdpSock)));
+ Os.write(mUdpSock, buf);
+ }
+ } catch(ErrnoException|IOException e) {
+ Log.e(TAG, "Can't send packet: ", e);
+ return false;
+ }
+ return true;
+ }
+
+ public ByteBuffer buildDiscoverWithRapidCommitPacket() {
+ startNewTransaction();
+ return DhcpPacket.buildDiscoverPacket(
+ DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
+ DO_UNICAST, REQUESTED_PARAMS, mRapidCommit);
+ }
+
+ private boolean sendDiscoverPacket() {
+ ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
+ DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
+ DO_UNICAST, REQUESTED_PARAMS, mRapidCommit);
+ return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
+ }
+
+ private boolean sendRequestPacket(
+ Inet4Address clientAddress, Inet4Address requestedAddress,
+ Inet4Address serverAddress, Inet4Address to) {
+ // TODO: should we use the transaction ID from the server?
+ final int encap = INADDR_ANY.equals(clientAddress)
+ ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
+
+ ByteBuffer packet = DhcpPacket.buildRequestPacket(
+ encap, mTransactionId, getSecs(), clientAddress,
+ DO_UNICAST, mHwAddr, requestedAddress,
+ serverAddress, REQUESTED_PARAMS, null);
+ String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
+ String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
+ " request=" + requestedAddress.getHostAddress() +
+ " serverid=" + serverStr;
+ return transmitPacket(packet, description, encap, to);
+ }
+
+ private void scheduleLeaseTimers() {
+ if (mDhcpLeaseExpiry == 0) {
+ Log.d(TAG, "Infinite lease, no timer scheduling needed");
+ return;
+ }
+
+ final long now = SystemClock.elapsedRealtime();
+
+ // TODO: consider getting the renew and rebind timers from T1 and T2.
+ // See also:
+ // https://tools.ietf.org/html/rfc2131#section-4.4.5
+ // https://tools.ietf.org/html/rfc1533#section-9.9
+ // https://tools.ietf.org/html/rfc1533#section-9.10
+ final long remainingDelay = mDhcpLeaseExpiry - now;
+ final long renewDelay = remainingDelay / 2;
+ final long rebindDelay = remainingDelay * 7 / 8;
+ mRenewAlarm.schedule(now + renewDelay);
+ mRebindAlarm.schedule(now + rebindDelay);
+ mExpiryAlarm.schedule(now + remainingDelay);
+ Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s");
+ Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s");
+ Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
+ }
+
+ private void notifySuccess() {
+ mController.sendMessage(
+ CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+ }
+
+ private void notifyFailure() {
+ mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
+ }
+
+ private void acceptDhcpResults(DhcpResults results, String msg) {
+ mDhcpLease = results;
+ if (mDhcpLease.dnsServers.isEmpty()) {
+ // supplement customized dns servers
+ String[] dnsServersList =
+ mContext.getResources().getStringArray(R.array.config_default_dns_servers);
+ for (final String dnsServer : dnsServersList) {
+ try {
+ mDhcpLease.dnsServers.add(InetAddresses.parseNumericAddress(dnsServer));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid default DNS server: " + dnsServer, e);
+ }
+ }
+ }
+ mOffer = null;
+ Log.d(TAG, msg + " lease: " + mDhcpLease);
+ notifySuccess();
+ }
+
+ private void clearDhcpState() {
+ mDhcpLease = null;
+ mDhcpLeaseExpiry = 0;
+ mOffer = null;
+ }
+
+ /**
+ * Quit the DhcpStateMachine.
+ *
+ * @hide
+ */
+ public void doQuit() {
+ Log.d(TAG, "doQuit");
+ quit();
+ }
+
+ @Override
+ protected void onQuitting() {
+ Log.d(TAG, "onQuitting");
+ mController.sendMessage(CMD_ON_QUIT);
+ }
+
+ abstract class LoggingState extends State {
+ private long mEnterTimeMs;
+
+ @Override
+ public void enter() {
+ if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
+ mEnterTimeMs = SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public void exit() {
+ long durationMs = SystemClock.elapsedRealtime() - mEnterTimeMs;
+ logState(getName(), (int) durationMs);
+ }
+
+ private String messageName(int what) {
+ return sMessageNames.get(what, Integer.toString(what));
+ }
+
+ private String messageToString(Message message) {
+ long now = SystemClock.uptimeMillis();
+ return new StringBuilder(" ")
+ .append(message.getWhen() - now)
+ .append(messageName(message.what))
+ .append(" ").append(message.arg1)
+ .append(" ").append(message.arg2)
+ .append(" ").append(message.obj)
+ .toString();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (MSG_DBG) {
+ Log.d(TAG, getName() + messageToString(message));
+ }
+ return NOT_HANDLED;
+ }
+
+ @Override
+ public String getName() {
+ // All DhcpClient's states are inner classes with a well defined name.
+ // Use getSimpleName() and avoid super's getName() creating new String instances.
+ return getClass().getSimpleName();
+ }
+ }
+
+ // Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
+ // CMD_PRE_DHCP_ACTION_COMPLETE, and then transitions to mOtherState.
+ abstract class WaitBeforeOtherState extends LoggingState {
+ protected State mOtherState;
+
+ @Override
+ public void enter() {
+ super.enter();
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ transitionTo(mOtherState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class StoppedState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_START_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ transitionTo(mWaitBeforeStartState);
+ } else {
+ transitionTo(mDhcpInitState);
+ }
+ return HANDLED;
+ case CMD_START_DHCP_RAPID_COMMIT:
+ mRapidCommit = message.arg1 == 1 ? true: false;
+ mDiscoverSent = message.arg2 == 1 ? true : false;
+ if (mRegisteredForPreDhcpNotification) {
+ if (mRapidCommit) {
+ transitionTo(mRapidCommitWaitBeforeStartState);
+ } else {
+ transitionTo(mWaitBeforeStartState);
+ }
+ } else {
+ if (mRapidCommit) {
+ transitionTo(mDhcpRapidCommitInitState);
+ } else {
+ transitionTo(mDhcpInitState);
+ }
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class DhcpRapidCommitInitState extends PacketRetransmittingState {
+ public DhcpRapidCommitInitState() {
+ super();
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+ if (!mDiscoverSent) {
+ startNewTransaction();
+ }
+ mLastInitEnterTime = SystemClock.elapsedRealtime();
+ }
+
+ protected boolean sendPacket() {
+ if (mDiscoverSent) {
+ mDiscoverSent = false;
+ return true;
+ }
+ return sendDiscoverPacket();
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if (packet instanceof DhcpOfferPacket) {
+ mOffer = packet.toDhcpResults();
+ if (mOffer != null) {
+ Log.d(TAG, "DhcpRapidCommitInitState:Got pending lease: " + mOffer);
+ transitionTo(mDhcpRequestingState);
+ }
+ } else if ((packet instanceof DhcpAckPacket)) {
+ DhcpResults results = packet.toDhcpResults();
+ Log.d(TAG,"Received ACK in DhcpRapidCommitInitState");
+ if (results != null) {
+ setDhcpLeaseExpiry(packet);
+ acceptDhcpResults(results, "Confirmed");
+ transitionTo(mConfiguringInterfaceState);
+ }
+ } else if (packet instanceof DhcpNakPacket) {
+ Log.d(TAG, "Received NAK in DhcpRapidCommitInitState, returning to INIT");
+ mOffer = null;
+ transitionTo(mDhcpInitState);
+ }
+ }
+ }
+
+ class WaitBeforeStartState extends WaitBeforeOtherState {
+ public WaitBeforeStartState(State otherState) {
+ super();
+ mOtherState = otherState;
+ }
+ }
+
+ class WaitBeforeRenewalState extends WaitBeforeOtherState {
+ public WaitBeforeRenewalState(State otherState) {
+ super();
+ mOtherState = otherState;
+ }
+ }
+
+ class DhcpState extends State {
+ @Override
+ public void enter() {
+ clearDhcpState();
+ if (initInterface() && initSockets()) {
+ mReceiveThread = new ReceiveThread();
+ mReceiveThread.start();
+ } else {
+ notifyFailure();
+ transitionTo(mStoppedState);
+ }
+ }
+
+ @Override
+ public void exit() {
+ if (mReceiveThread != null) {
+ mReceiveThread.halt(); // Also closes sockets.
+ mReceiveThread = null;
+ }
+ clearDhcpState();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ transitionTo(mStoppedState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ public boolean isValidPacket(DhcpPacket packet) {
+ // TODO: check checksum.
+ int xid = packet.getTransactionId();
+ if (xid != mTransactionId) {
+ Log.d(TAG, "Unexpected transaction ID " + xid + ", expected " + mTransactionId);
+ return false;
+ }
+ if (!Arrays.equals(packet.getClientMac(), mHwAddr)) {
+ Log.d(TAG, "MAC addr mismatch: got " +
+ HexDump.toHexString(packet.getClientMac()) + ", expected " +
+ HexDump.toHexString(packet.getClientMac()));
+ return false;
+ }
+ return true;
+ }
+
+ public void setDhcpLeaseExpiry(DhcpPacket packet) {
+ long leaseTimeMillis = packet.getLeaseTimeMillis();
+ mDhcpLeaseExpiry =
+ (leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0;
+ }
+
+ /**
+ * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
+ * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
+ * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
+ * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
+ * state.
+ *
+ * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
+ * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
+ * sent by the receive thread. They may also set mTimeout and implement timeout.
+ */
+ abstract class PacketRetransmittingState extends LoggingState {
+
+ private int mTimer;
+ protected int mTimeout = 0;
+
+ @Override
+ public void enter() {
+ super.enter();
+ initTimer();
+ maybeInitTimeout();
+ sendMessage(CMD_KICK);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case CMD_KICK:
+ sendPacket();
+ scheduleKick();
+ return HANDLED;
+ case CMD_RECEIVED_PACKET:
+ receivePacket((DhcpPacket) message.obj);
+ return HANDLED;
+ case CMD_TIMEOUT:
+ timeout();
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ mKickAlarm.cancel();
+ mTimeoutAlarm.cancel();
+ }
+
+ abstract protected boolean sendPacket();
+ abstract protected void receivePacket(DhcpPacket packet);
+ protected void timeout() {}
+
+ protected void initTimer() {
+ mTimer = FIRST_TIMEOUT_MS;
+ }
+
+ protected int jitterTimer(int baseTimer) {
+ int maxJitter = baseTimer / 10;
+ int jitter = mRandom.nextInt(2 * maxJitter) - maxJitter;
+ return baseTimer + jitter;
+ }
+
+ protected void scheduleKick() {
+ long now = SystemClock.elapsedRealtime();
+ long timeout = jitterTimer(mTimer);
+ long alarmTime = now + timeout;
+ mKickAlarm.schedule(alarmTime);
+ mTimer *= 2;
+ if (mTimer > MAX_TIMEOUT_MS) {
+ mTimer = MAX_TIMEOUT_MS;
+ }
+ }
+
+ protected void maybeInitTimeout() {
+ if (mTimeout > 0) {
+ long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
+ mTimeoutAlarm.schedule(alarmTime);
+ }
+ }
+ }
+
+ class DhcpInitState extends PacketRetransmittingState {
+ public DhcpInitState() {
+ super();
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+ startNewTransaction();
+ mLastInitEnterTime = SystemClock.elapsedRealtime();
+ }
+
+ protected boolean sendPacket() {
+ return sendDiscoverPacket();
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if (!(packet instanceof DhcpOfferPacket)) return;
+ mOffer = packet.toDhcpResults();
+ if (mOffer != null) {
+ Log.d(TAG, "Got pending lease: " + mOffer);
+ transitionTo(mDhcpRequestingState);
+ }
+ }
+ }
+
+ // Not implemented. We request the first offer we receive.
+ class DhcpSelectingState extends LoggingState {
+ }
+
+ class DhcpRequestingState extends PacketRetransmittingState {
+ public DhcpRequestingState() {
+ mTimeout = DHCP_TIMEOUT_MS / 2;
+ }
+
+ protected boolean sendPacket() {
+ return sendRequestPacket(
+ INADDR_ANY, // ciaddr
+ (Inet4Address) mOffer.ipAddress.getAddress(), // DHCP_REQUESTED_IP
+ (Inet4Address) mOffer.serverAddress, // DHCP_SERVER_IDENTIFIER
+ INADDR_BROADCAST); // packet destination address
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if ((packet instanceof DhcpAckPacket)) {
+ DhcpResults results = packet.toDhcpResults();
+ if (results != null) {
+ setDhcpLeaseExpiry(packet);
+ acceptDhcpResults(results, "Confirmed");
+ transitionTo(mConfiguringInterfaceState);
+ }
+ } else if (packet instanceof DhcpNakPacket) {
+ // TODO: Wait a while before returning into INIT state.
+ Log.d(TAG, "Received NAK, returning to INIT");
+ mOffer = null;
+ transitionTo(mDhcpInitState);
+ }
+ }
+
+ @Override
+ protected void timeout() {
+ // After sending REQUESTs unsuccessfully for a while, go back to init.
+ transitionTo(mDhcpInitState);
+ }
+ }
+
+ class DhcpHaveLeaseState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case CMD_EXPIRE_DHCP:
+ Log.d(TAG, "Lease expired!");
+ notifyFailure();
+ transitionTo(mDhcpInitState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ @Override
+ public void exit() {
+ // Clear any extant alarms.
+ mRenewAlarm.cancel();
+ mRebindAlarm.cancel();
+ mExpiryAlarm.cancel();
+ clearDhcpState();
+ // Tell IpManager to clear the IPv4 address. There is no need to
+ // wait for confirmation since any subsequent packets are sent from
+ // INADDR_ANY anyway (DISCOVER, REQUEST).
+ mController.sendMessage(CMD_CLEAR_LINKADDRESS);
+ }
+ }
+
+ class ConfiguringInterfaceState extends LoggingState {
+ @Override
+ public void enter() {
+ super.enter();
+ mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case EVENT_LINKADDRESS_CONFIGURED:
+ transitionTo(mDhcpBoundState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class DhcpBoundState extends LoggingState {
+ @Override
+ public void enter() {
+ super.enter();
+ if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) {
+ // There's likely no point in going into DhcpInitState here, we'll probably
+ // just repeat the transaction, get the same IP address as before, and fail.
+ //
+ // NOTE: It is observed that connectUdpSock() basically never fails, due to
+ // SO_BINDTODEVICE. Examining the local socket address shows it will happily
+ // return an IPv4 address from another interface, or even return "0.0.0.0".
+ //
+ // TODO: Consider deleting this check, following testing on several kernels.
+ notifyFailure();
+ transitionTo(mStoppedState);
+ }
+
+ scheduleLeaseTimers();
+ logTimeToBoundState();
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ mLastBoundExitTime = SystemClock.elapsedRealtime();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case CMD_RENEW_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ transitionTo(mWaitBeforeRenewalState);
+ } else {
+ transitionTo(mDhcpRenewingState);
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ private void logTimeToBoundState() {
+ long now = SystemClock.elapsedRealtime();
+ if (mLastBoundExitTime > mLastInitEnterTime) {
+ logState(EVENT_RENEWING_BOUND, (int) (now - mLastBoundExitTime));
+ } else {
+ logState(EVENT_INITIAL_BOUND, (int) (now - mLastInitEnterTime));
+ }
+ }
+ }
+
+ abstract class DhcpReacquiringState extends PacketRetransmittingState {
+ protected String mLeaseMsg;
+
+ @Override
+ public void enter() {
+ super.enter();
+ startNewTransaction();
+ }
+
+ abstract protected Inet4Address packetDestination();
+
+ protected boolean sendPacket() {
+ return sendRequestPacket(
+ (Inet4Address) mDhcpLease.ipAddress.getAddress(), // ciaddr
+ INADDR_ANY, // DHCP_REQUESTED_IP
+ null, // DHCP_SERVER_IDENTIFIER
+ packetDestination()); // packet destination address
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if ((packet instanceof DhcpAckPacket)) {
+ final DhcpResults results = packet.toDhcpResults();
+ if (results != null) {
+ if (!mDhcpLease.ipAddress.equals(results.ipAddress)) {
+ Log.d(TAG, "Renewed lease not for our current IP address!");
+ notifyFailure();
+ transitionTo(mDhcpInitState);
+ }
+ setDhcpLeaseExpiry(packet);
+ // Updating our notion of DhcpResults here only causes the
+ // DNS servers and routes to be updated in LinkProperties
+ // in IpManager and by any overridden relevant handlers of
+ // the registered IpManager.Callback. IP address changes
+ // are not supported here.
+ acceptDhcpResults(results, mLeaseMsg);
+ transitionTo(mDhcpBoundState);
+ }
+ } else if (packet instanceof DhcpNakPacket) {
+ Log.d(TAG, "Received NAK, returning to INIT");
+ notifyFailure();
+ transitionTo(mDhcpInitState);
+ }
+ }
+ }
+
+ class DhcpRenewingState extends DhcpReacquiringState {
+ public DhcpRenewingState() {
+ mLeaseMsg = "Renewed";
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (super.processMessage(message) == HANDLED) {
+ return HANDLED;
+ }
+
+ switch (message.what) {
+ case CMD_REBIND_DHCP:
+ transitionTo(mDhcpRebindingState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ @Override
+ protected Inet4Address packetDestination() {
+ // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
+ // http://b/25343517 . Try to make things work anyway by using broadcast renews.
+ return (mDhcpLease.serverAddress != null) ?
+ mDhcpLease.serverAddress : INADDR_BROADCAST;
+ }
+ }
+
+ class DhcpRebindingState extends DhcpReacquiringState {
+ public DhcpRebindingState() {
+ mLeaseMsg = "Rebound";
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+
+ // We need to broadcast and possibly reconnect the socket to a
+ // completely different server.
+ closeSocketQuietly(mUdpSock);
+ if (!initUdpSocket()) {
+ Log.e(TAG, "Failed to recreate UDP socket");
+ transitionTo(mDhcpInitState);
+ }
+ }
+
+ @Override
+ protected Inet4Address packetDestination() {
+ return INADDR_BROADCAST;
+ }
+ }
+
+ class DhcpInitRebootState extends LoggingState {
+ }
+
+ class DhcpRebootingState extends LoggingState {
+ }
+
+ private void logError(int errorCode) {
+ mMetricsLog.log(mIfaceName, new DhcpErrorEvent(errorCode));
+ }
+
+ private void logState(String name, int durationMs) {
+ final DhcpClientEvent event = new DhcpClientEvent.Builder()
+ .setMsg(name)
+ .setDurationMs(durationMs)
+ .build();
+ mMetricsLog.log(mIfaceName, event);
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
new file mode 100644
index 0000000..19beb08
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+
+/**
+ * This class implements the DHCP-DISCOVER packet.
+ */
+class DhcpDiscoverPacket extends DhcpPacket {
+ /**
+ * The IP address of the client which sent this packet.
+ */
+ final Inet4Address mSrcIp;
+
+ /**
+ * Generates a DISCOVER packet with the specified parameters.
+ */
+ DhcpDiscoverPacket(int transId, short secs, Inet4Address relayIp, byte[] clientMac,
+ boolean broadcast, Inet4Address srcIp) {
+ super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, relayIp, clientMac, broadcast);
+ mSrcIp = srcIp;
+ }
+ DhcpDiscoverPacket(int transId, short secs, byte[] clientMac, boolean broadcast,
+ boolean rapidCommit) {
+ super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY,
+ clientMac, broadcast, rapidCommit);
+ mSrcIp = INADDR_ANY;
+ }
+
+ public String toString() {
+ String s = super.toString();
+ return s + " DISCOVER " +
+ (mBroadcast ? "broadcast " : "unicast ");
+ }
+
+ /**
+ * Fills in a packet with the requested DISCOVER parameters.
+ */
+ public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
+ ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
+ fillInPacket(encap, INADDR_BROADCAST, mSrcIp, destUdp, srcUdp, result, DHCP_BOOTREQUEST,
+ mBroadcast);
+ result.flip();
+ return result;
+ }
+
+ /**
+ * Adds optional parameters to a DISCOVER packet.
+ */
+ void finishPacket(ByteBuffer buffer) {
+ addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DISCOVER);
+ addTlv(buffer, DHCP_CLIENT_IDENTIFIER, getClientId());
+ addCommonClientTlvs(buffer);
+ addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
+ if (mRapidCommit) {
+ addTlv(buffer, DHCP_OPTION_RAPID_COMMIT);
+ }
+ addTlvEnd(buffer);
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
new file mode 100644
index 0000000..c382733
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
@@ -0,0 +1,1428 @@
+package android.net.dhcp;
+
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
+import android.annotation.Nullable;
+import android.net.DhcpResults;
+import android.net.LinkAddress;
+import android.net.metrics.DhcpErrorEvent;
+import android.net.shared.Inet4AddressUtils;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.system.OsConstants;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.UnsupportedEncodingException;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Defines basic data and operations needed to build and use packets for the
+ * DHCP protocol. Subclasses create the specific packets used at each
+ * stage of the negotiation.
+ *
+ * @hide
+ */
+public abstract class DhcpPacket {
+ protected static final String TAG = "DhcpPacket";
+
+ // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack.
+ private static final int IPV4_MIN_MTU = 68;
+
+ // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
+ // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
+ // DHCP client timeout.
+ public static final int MINIMUM_LEASE = 60;
+ public static final int INFINITE_LEASE = (int) 0xffffffff;
+
+ public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY;
+ public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL;
+ public static final byte[] ETHER_BROADCAST = new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ };
+
+ /**
+ * Packet encapsulations.
+ */
+ public static final int ENCAP_L2 = 0; // EthernetII header included
+ public static final int ENCAP_L3 = 1; // IP/UDP header included
+ public static final int ENCAP_BOOTP = 2; // BOOTP contents only
+
+ /**
+ * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
+ */
+ public static final int MIN_PACKET_LENGTH_BOOTP = 236; // See diagram in RFC 2131, section 2.
+ public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
+ public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
+
+ public static final int HWADDR_LEN = 16;
+ public static final int MAX_OPTION_LEN = 255;
+
+ /**
+ * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+ * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+ * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+ * because in general it is risky to assume that the hardware is able to send/receive packets
+ * larger than 1500 bytes even if the network supports it.
+ */
+ private static final int MIN_MTU = 1280;
+ private static final int MAX_MTU = 1500;
+
+ /**
+ * IP layer definitions.
+ */
+ private static final byte IP_TYPE_UDP = (byte) 0x11;
+
+ /**
+ * IP: Version 4, Header Length 20 bytes
+ */
+ private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
+
+ /**
+ * IP: Flags 0, Fragment Offset 0, Don't Fragment
+ */
+ private static final short IP_FLAGS_OFFSET = (short) 0x4000;
+
+ /**
+ * IP: TOS
+ */
+ private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
+
+ /**
+ * IP: TTL -- use default 64 from RFC1340
+ */
+ private static final byte IP_TTL = (byte) 0x40;
+
+ /**
+ * The client DHCP port.
+ */
+ static final short DHCP_CLIENT = (short) 68;
+
+ /**
+ * The server DHCP port.
+ */
+ static final short DHCP_SERVER = (short) 67;
+
+ /**
+ * The message op code indicating a request from a client.
+ */
+ protected static final byte DHCP_BOOTREQUEST = (byte) 1;
+
+ /**
+ * The message op code indicating a response from the server.
+ */
+ protected static final byte DHCP_BOOTREPLY = (byte) 2;
+
+ /**
+ * The code type used to identify an Ethernet MAC address in the
+ * Client-ID field.
+ */
+ protected static final byte CLIENT_ID_ETHER = (byte) 1;
+
+ /**
+ * The maximum length of a packet that can be constructed.
+ */
+ protected static final int MAX_LENGTH = 1500;
+
+ /**
+ * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
+ */
+ private static final int DHCP_MAGIC_COOKIE = 0x63825363;
+
+ /**
+ * DHCP Optional Type: DHCP Subnet Mask
+ */
+ protected static final byte DHCP_SUBNET_MASK = 1;
+ protected Inet4Address mSubnetMask;
+
+ /**
+ * DHCP Optional Type: DHCP Router
+ */
+ protected static final byte DHCP_ROUTER = 3;
+ protected List <Inet4Address> mGateways;
+
+ /**
+ * DHCP Optional Type: DHCP DNS Server
+ */
+ protected static final byte DHCP_DNS_SERVER = 6;
+ protected List<Inet4Address> mDnsServers;
+
+ /**
+ * DHCP Optional Type: DHCP Host Name
+ */
+ protected static final byte DHCP_HOST_NAME = 12;
+ protected String mHostName;
+
+ /**
+ * DHCP Optional Type: DHCP DOMAIN NAME
+ */
+ protected static final byte DHCP_DOMAIN_NAME = 15;
+ protected String mDomainName;
+
+ /**
+ * DHCP Optional Type: DHCP Interface MTU
+ */
+ protected static final byte DHCP_MTU = 26;
+ protected Short mMtu;
+
+ /**
+ * DHCP Optional Type: DHCP BROADCAST ADDRESS
+ */
+ protected static final byte DHCP_BROADCAST_ADDRESS = 28;
+ protected Inet4Address mBroadcastAddress;
+
+ /**
+ * DHCP Optional Type: Vendor specific information
+ */
+ protected static final byte DHCP_VENDOR_INFO = 43;
+ protected String mVendorInfo;
+
+ /**
+ * Value of the vendor specific option used to indicate that the network is metered
+ */
+ public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
+
+ /**
+ * DHCP Optional Type: Option overload option
+ */
+ protected static final byte DHCP_OPTION_OVERLOAD = 52;
+
+ /**
+ * Possible values of the option overload option.
+ */
+ private static final byte OPTION_OVERLOAD_FILE = 1;
+ private static final byte OPTION_OVERLOAD_SNAME = 2;
+ private static final byte OPTION_OVERLOAD_BOTH = 3;
+
+ /**
+ * DHCP Optional Type: DHCP Requested IP Address
+ */
+ protected static final byte DHCP_REQUESTED_IP = 50;
+ protected Inet4Address mRequestedIp;
+
+ /**
+ * DHCP Optional Type: DHCP Lease Time
+ */
+ protected static final byte DHCP_LEASE_TIME = 51;
+ protected Integer mLeaseTime;
+
+ /**
+ * DHCP Optional Type: DHCP Message Type
+ */
+ protected static final byte DHCP_MESSAGE_TYPE = 53;
+ // the actual type values
+ protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
+ protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
+ protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
+ protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
+ protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
+ protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
+ protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
+ protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
+
+ /**
+ * DHCP Optional Type: DHCP Server Identifier
+ */
+ protected static final byte DHCP_SERVER_IDENTIFIER = 54;
+ protected Inet4Address mServerIdentifier;
+
+ /**
+ * DHCP Optional Type: DHCP Parameter List
+ */
+ protected static final byte DHCP_PARAMETER_LIST = 55;
+ protected byte[] mRequestedParams;
+
+ /**
+ * DHCP Optional Type: DHCP MESSAGE
+ */
+ protected static final byte DHCP_MESSAGE = 56;
+ protected String mMessage;
+
+ /**
+ * DHCP Optional Type: Maximum DHCP Message Size
+ */
+ protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
+ protected Short mMaxMessageSize;
+
+ /**
+ * DHCP Optional Type: DHCP Renewal Time Value
+ */
+ protected static final byte DHCP_RENEWAL_TIME = 58;
+ protected Integer mT1;
+
+ /**
+ * DHCP Optional Type: Rebinding Time Value
+ */
+ protected static final byte DHCP_REBINDING_TIME = 59;
+ protected Integer mT2;
+
+ /**
+ * DHCP Optional Type: Vendor Class Identifier
+ */
+ protected static final byte DHCP_VENDOR_CLASS_ID = 60;
+ protected String mVendorId;
+
+ /**
+ * DHCP Optional Type: DHCP Client Identifier
+ */
+ protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
+ protected byte[] mClientId;
+
+ /**
+ * DHCP zero-length option code: rapid commit
+ */
+ protected static final byte DHCP_OPTION_RAPID_COMMIT = 80;
+
+ /**
+ * DHCP zero-length option code: pad
+ */
+ protected static final byte DHCP_OPTION_PAD = 0x00;
+
+ /**
+ * DHCP zero-length option code: end of options
+ */
+ protected static final byte DHCP_OPTION_END = (byte) 0xff;
+
+ /**
+ * The transaction identifier used in this particular DHCP negotiation
+ */
+ protected final int mTransId;
+
+ /**
+ * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
+ */
+ protected final short mSecs;
+
+ /**
+ * The IP address of the client host. This address is typically
+ * proposed by the client (from an earlier DHCP negotiation) or
+ * supplied by the server.
+ */
+ protected final Inet4Address mClientIp;
+ protected final Inet4Address mYourIp;
+ private final Inet4Address mNextIp;
+ protected final Inet4Address mRelayIp;
+
+ /**
+ * Does the client request a broadcast response?
+ */
+ protected boolean mBroadcast;
+
+ /**
+ * The six-octet MAC of the client.
+ */
+ protected final byte[] mClientMac;
+
+ /**
+ * The server host name from server.
+ */
+ protected String mServerHostName;
+
+ /**
+ * Whether the packet should be built with rapid commit option
+ */
+ protected boolean mRapidCommit;
+
+ /**
+ * Asks the packet object to create a ByteBuffer serialization of
+ * the packet for transmission.
+ */
+ public abstract ByteBuffer buildPacket(int encap, short destUdp,
+ short srcUdp);
+
+ /**
+ * Allows the concrete class to fill in packet-type-specific details,
+ * typically optional parameters at the end of the packet.
+ */
+ abstract void finishPacket(ByteBuffer buffer);
+
+ // Set in unit tests, to ensure that the test does not break when run on different devices and
+ // on different releases.
+ static String testOverrideVendorId = null;
+ static String testOverrideHostname = null;
+
+ protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
+ byte[] clientMac, boolean broadcast, boolean rapidCommit) {
+ mTransId = transId;
+ mSecs = secs;
+ mClientIp = clientIp;
+ mYourIp = yourIp;
+ mNextIp = nextIp;
+ mRelayIp = relayIp;
+ mClientMac = clientMac;
+ mBroadcast = broadcast;
+ mRapidCommit = rapidCommit;
+ }
+
+ protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
+ byte[] clientMac, boolean broadcast) {
+ this(transId, secs, clientIp, yourIp, nextIp,
+ relayIp, clientMac, broadcast, false);
+ }
+
+ /**
+ * Returns the transaction ID.
+ */
+ public int getTransactionId() {
+ return mTransId;
+ }
+
+ /**
+ * Returns the client MAC.
+ */
+ public byte[] getClientMac() {
+ return mClientMac;
+ }
+
+ // TODO: refactor DhcpClient to set clientId when constructing packets and remove
+ // hasExplicitClientId logic
+ /**
+ * Returns whether a client ID was set in the options for this packet.
+ */
+ public boolean hasExplicitClientId() {
+ return mClientId != null;
+ }
+
+ /**
+ * Convenience method to return the client ID if it was set explicitly, or null otherwise.
+ */
+ @Nullable
+ public byte[] getExplicitClientIdOrNull() {
+ return hasExplicitClientId() ? getClientId() : null;
+ }
+
+ /**
+ * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
+ * based on the hardware address.
+ */
+ public byte[] getClientId() {
+ final byte[] clientId;
+ if (hasExplicitClientId()) {
+ clientId = Arrays.copyOf(mClientId, mClientId.length);
+ } else {
+ clientId = new byte[mClientMac.length + 1];
+ clientId[0] = CLIENT_ID_ETHER;
+ System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
+ }
+ return clientId;
+ }
+
+ /**
+ * Returns whether a parameter is included in the parameter request list option of this packet.
+ *
+ * <p>If there is no parameter request list option in the packet, false is returned.
+ *
+ * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
+ */
+ public boolean hasRequestedParam(byte paramId) {
+ if (mRequestedParams == null) {
+ return false;
+ }
+
+ for (byte reqParam : mRequestedParams) {
+ if (reqParam == paramId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a new L3 packet (including IP header) containing the
+ * DHCP udp packet. This method relies upon the delegated method
+ * finishPacket() to insert the per-packet contents.
+ */
+ protected void fillInPacket(int encap, Inet4Address destIp,
+ Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
+ byte requestCode, boolean broadcast) {
+ byte[] destIpArray = destIp.getAddress();
+ byte[] srcIpArray = srcIp.getAddress();
+ int ipHeaderOffset = 0;
+ int ipLengthOffset = 0;
+ int ipChecksumOffset = 0;
+ int endIpHeader = 0;
+ int udpHeaderOffset = 0;
+ int udpLengthOffset = 0;
+ int udpChecksumOffset = 0;
+
+ buf.clear();
+ buf.order(ByteOrder.BIG_ENDIAN);
+
+ if (encap == ENCAP_L2) {
+ buf.put(ETHER_BROADCAST);
+ buf.put(mClientMac);
+ buf.putShort((short) OsConstants.ETH_P_IP);
+ }
+
+ // if a full IP packet needs to be generated, put the IP & UDP
+ // headers in place, and pre-populate with artificial values
+ // needed to seed the IP checksum.
+ if (encap <= ENCAP_L3) {
+ ipHeaderOffset = buf.position();
+ buf.put(IP_VERSION_HEADER_LEN);
+ buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY
+ ipLengthOffset = buf.position();
+ buf.putShort((short)0); // length
+ buf.putShort((short)0); // id
+ buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
+ buf.put(IP_TTL); // TTL: use default 64 from RFC1340
+ buf.put(IP_TYPE_UDP);
+ ipChecksumOffset = buf.position();
+ buf.putShort((short) 0); // checksum
+
+ buf.put(srcIpArray);
+ buf.put(destIpArray);
+ endIpHeader = buf.position();
+
+ // UDP header
+ udpHeaderOffset = buf.position();
+ buf.putShort(srcUdp);
+ buf.putShort(destUdp);
+ udpLengthOffset = buf.position();
+ buf.putShort((short) 0); // length
+ udpChecksumOffset = buf.position();
+ buf.putShort((short) 0); // UDP checksum -- initially zero
+ }
+
+ // DHCP payload
+ buf.put(requestCode);
+ buf.put((byte) 1); // Hardware Type: Ethernet
+ buf.put((byte) mClientMac.length); // Hardware Address Length
+ buf.put((byte) 0); // Hop Count
+ buf.putInt(mTransId); // Transaction ID
+ buf.putShort(mSecs); // Elapsed Seconds
+
+ if (broadcast) {
+ buf.putShort((short) 0x8000); // Flags
+ } else {
+ buf.putShort((short) 0x0000); // Flags
+ }
+
+ buf.put(mClientIp.getAddress());
+ buf.put(mYourIp.getAddress());
+ buf.put(mNextIp.getAddress());
+ buf.put(mRelayIp.getAddress());
+ buf.put(mClientMac);
+ buf.position(buf.position() +
+ (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
+ + 64 // empty server host name (64 bytes)
+ + 128); // empty boot file name (128 bytes)
+ buf.putInt(DHCP_MAGIC_COOKIE); // magic number
+ finishPacket(buf);
+
+ // round up to an even number of octets
+ if ((buf.position() & 1) == 1) {
+ buf.put((byte) 0);
+ }
+
+ // If an IP packet is being built, the IP & UDP checksums must be
+ // computed.
+ if (encap <= ENCAP_L3) {
+ // fix UDP header: insert length
+ short udpLen = (short)(buf.position() - udpHeaderOffset);
+ buf.putShort(udpLengthOffset, udpLen);
+ // fix UDP header: checksum
+ // checksum for UDP at udpChecksumOffset
+ int udpSeed = 0;
+
+ // apply IPv4 pseudo-header. Read IP address src and destination
+ // values from the IP header and accumulate checksum.
+ udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
+ udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
+ udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
+ udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
+
+ // accumulate extra data for the pseudo-header
+ udpSeed += IP_TYPE_UDP;
+ udpSeed += udpLen;
+ // and compute UDP checksum
+ buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
+ udpHeaderOffset,
+ buf.position()));
+ // fix IP header: insert length
+ buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
+ // fixup IP-header checksum
+ buf.putShort(ipChecksumOffset,
+ (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
+ }
+ }
+
+ /**
+ * Converts a signed short value to an unsigned int value. Needed
+ * because Java does not have unsigned types.
+ */
+ private static int intAbs(short v) {
+ return v & 0xFFFF;
+ }
+
+ /**
+ * Performs an IP checksum (used in IP header and across UDP
+ * payload) on the specified portion of a ByteBuffer. The seed
+ * allows the checksum to commence with a specified value.
+ */
+ private int checksum(ByteBuffer buf, int seed, int start, int end) {
+ int sum = seed;
+ int bufPosition = buf.position();
+
+ // set position of original ByteBuffer, so that the ShortBuffer
+ // will be correctly initialized
+ buf.position(start);
+ ShortBuffer shortBuf = buf.asShortBuffer();
+
+ // re-set ByteBuffer position
+ buf.position(bufPosition);
+
+ short[] shortArray = new short[(end - start) / 2];
+ shortBuf.get(shortArray);
+
+ for (short s : shortArray) {
+ sum += intAbs(s);
+ }
+
+ start += shortArray.length * 2;
+
+ // see if a singleton byte remains
+ if (end != start) {
+ short b = buf.get(start);
+
+ // make it unsigned
+ if (b < 0) {
+ b += 256;
+ }
+
+ sum += b * 256;
+ }
+
+ sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
+ sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
+ int negated = ~sum;
+ return intAbs((short) negated);
+ }
+
+ /**
+ * Adds an optional parameter not containing any payload.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type) {
+ buf.put(type);
+ buf.put((byte) 0);
+ }
+
+ /**
+ * Adds an optional parameter containing a single byte value.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, byte value) {
+ buf.put(type);
+ buf.put((byte) 1);
+ buf.put(value);
+ }
+
+ /**
+ * Adds an optional parameter containing an array of bytes.
+ *
+ * <p>This method is a no-op if the payload argument is null.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
+ if (payload != null) {
+ if (payload.length > MAX_OPTION_LEN) {
+ throw new IllegalArgumentException("DHCP option too long: "
+ + payload.length + " vs. " + MAX_OPTION_LEN);
+ }
+ buf.put(type);
+ buf.put((byte) payload.length);
+ buf.put(payload);
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing an IP address.
+ *
+ * <p>This method is a no-op if the address argument is null.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
+ if (addr != null) {
+ addTlv(buf, type, addr.getAddress());
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing a list of IP addresses.
+ *
+ * <p>This method is a no-op if the addresses argument is null or empty.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
+ if (addrs == null || addrs.size() == 0) return;
+
+ int optionLen = 4 * addrs.size();
+ if (optionLen > MAX_OPTION_LEN) {
+ throw new IllegalArgumentException("DHCP option too long: "
+ + optionLen + " vs. " + MAX_OPTION_LEN);
+ }
+
+ buf.put(type);
+ buf.put((byte)(optionLen));
+
+ for (Inet4Address addr : addrs) {
+ buf.put(addr.getAddress());
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing a short integer.
+ *
+ * <p>This method is a no-op if the value argument is null.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
+ if (value != null) {
+ buf.put(type);
+ buf.put((byte) 2);
+ buf.putShort(value.shortValue());
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing a simple integer.
+ *
+ * <p>This method is a no-op if the value argument is null.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
+ if (value != null) {
+ buf.put(type);
+ buf.put((byte) 4);
+ buf.putInt(value.intValue());
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing an ASCII string.
+ *
+ * <p>This method is a no-op if the string argument is null.
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
+ if (str != null) {
+ try {
+ addTlv(buf, type, str.getBytes("US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("String is not US-ASCII: " + str);
+ }
+ }
+ }
+
+ /**
+ * Adds the special end-of-optional-parameters indicator.
+ */
+ protected static void addTlvEnd(ByteBuffer buf) {
+ buf.put((byte) 0xFF);
+ }
+
+ private String getVendorId() {
+ if (testOverrideVendorId != null) return testOverrideVendorId;
+ return "android-dhcp-" + Build.VERSION.RELEASE;
+ }
+
+ private String getHostname() {
+ if (testOverrideHostname != null) return testOverrideHostname;
+ return SystemProperties.get("net.hostname");
+ }
+
+ /**
+ * Adds common client TLVs.
+ *
+ * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
+ * methods to take them.
+ */
+ protected void addCommonClientTlvs(ByteBuffer buf) {
+ addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
+ addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
+ final String hn = getHostname();
+ if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
+ }
+
+ protected void addCommonServerTlvs(ByteBuffer buf) {
+ addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
+ if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
+ // The client should renew at 1/2 the lease-expiry interval
+ addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
+ // Default rebinding time is set as below by RFC2131
+ addTlv(buf, DHCP_REBINDING_TIME,
+ (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
+ }
+ addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
+ addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
+ addTlv(buf, DHCP_ROUTER, mGateways);
+ addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
+ addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
+ addTlv(buf, DHCP_HOST_NAME, mHostName);
+ addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
+ if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
+ addTlv(buf, DHCP_MTU, mMtu);
+ }
+ }
+
+ /**
+ * Converts a MAC from an array of octets to an ASCII string.
+ */
+ public static String macToString(byte[] mac) {
+ String macAddr = "";
+
+ for (int i = 0; i < mac.length; i++) {
+ String hexString = "0" + Integer.toHexString(mac[i]);
+
+ // substring operation grabs the last 2 digits: this
+ // allows signed bytes to be converted correctly.
+ macAddr += hexString.substring(hexString.length() - 2);
+
+ if (i != (mac.length - 1)) {
+ macAddr += ":";
+ }
+ }
+
+ return macAddr;
+ }
+
+ public String toString() {
+ String macAddr = macToString(mClientMac);
+
+ return macAddr;
+ }
+
+ /**
+ * Reads a four-octet value from a ByteBuffer and construct
+ * an IPv4 address from that value.
+ */
+ private static Inet4Address readIpAddress(ByteBuffer packet) {
+ Inet4Address result = null;
+ byte[] ipAddr = new byte[4];
+ packet.get(ipAddr);
+
+ try {
+ result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
+ } catch (UnknownHostException ex) {
+ // ipAddr is numeric, so this should not be
+ // triggered. However, if it is, just nullify
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * Reads a string of specified length from the buffer.
+ */
+ private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
+ byte[] bytes = new byte[byteCount];
+ buf.get(bytes);
+ int length = bytes.length;
+ if (!nullOk) {
+ // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+ // name) are passed to netd via FrameworkListener, which refuses arguments containing
+ // null bytes. We don't do this by default because vendorInfo is an opaque string which
+ // could in theory contain null bytes.
+ for (length = 0; length < bytes.length; length++) {
+ if (bytes[length] == 0) {
+ break;
+ }
+ }
+ }
+ return new String(bytes, 0, length, StandardCharsets.US_ASCII);
+ }
+
+ private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
+ return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
+ }
+
+ private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
+ return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
+ }
+
+ public static class ParseException extends Exception {
+ public final int errorCode;
+ public ParseException(int errorCode, String msg, Object... args) {
+ super(String.format(msg, args));
+ this.errorCode = errorCode;
+ }
+ }
+
+ /**
+ * Creates a concrete DhcpPacket from the supplied ByteBuffer. The
+ * buffer may have an L2 encapsulation (which is the full EthernetII
+ * format starting with the source-address MAC) or an L3 encapsulation
+ * (which starts with the IP header).
+ * <br>
+ * A subset of the optional parameters are parsed and are stored
+ * in object fields.
+ */
+ @VisibleForTesting
+ static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
+ {
+ // bootp parameters
+ int transactionId;
+ short secs;
+ Inet4Address clientIp;
+ Inet4Address yourIp;
+ Inet4Address nextIp;
+ Inet4Address relayIp;
+ byte[] clientMac;
+ byte[] clientId = null;
+ List<Inet4Address> dnsServers = new ArrayList<>();
+ List<Inet4Address> gateways = new ArrayList<>(); // aka router
+ Inet4Address serverIdentifier = null;
+ Inet4Address netMask = null;
+ String message = null;
+ String vendorId = null;
+ String vendorInfo = null;
+ byte[] expectedParams = null;
+ String hostName = null;
+ String domainName = null;
+ Inet4Address ipSrc = null;
+ Inet4Address ipDst = null;
+ Inet4Address bcAddr = null;
+ Inet4Address requestedIp = null;
+ String serverHostName;
+ byte optionOverload = 0;
+
+ // The following are all unsigned integers. Internally we store them as signed integers of
+ // the same length because that way we're guaranteed that they can't be out of the range of
+ // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
+ // to cast it.
+ Short mtu = null;
+ Short maxMessageSize = null;
+ Integer leaseTime = null;
+ Integer T1 = null;
+ Integer T2 = null;
+
+ // dhcp options
+ byte dhcpType = (byte) 0xFF;
+
+ packet.order(ByteOrder.BIG_ENDIAN);
+
+ // check to see if we need to parse L2, IP, and UDP encaps
+ if (pktType == ENCAP_L2) {
+ if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+ throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
+ "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
+ }
+
+ byte[] l2dst = new byte[6];
+ byte[] l2src = new byte[6];
+
+ packet.get(l2dst);
+ packet.get(l2src);
+
+ short l2type = packet.getShort();
+
+ if (l2type != OsConstants.ETH_P_IP) {
+ throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
+ "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
+ }
+ }
+
+ if (pktType <= ENCAP_L3) {
+ if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+ throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
+ "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
+ }
+
+ byte ipTypeAndLength = packet.get();
+ int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
+ if (ipVersion != 4) {
+ throw new ParseException(
+ DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
+ }
+
+ // System.out.println("ipType is " + ipType);
+ byte ipDiffServicesField = packet.get();
+ short ipTotalLength = packet.getShort();
+ short ipIdentification = packet.getShort();
+ byte ipFlags = packet.get();
+ byte ipFragOffset = packet.get();
+ byte ipTTL = packet.get();
+ byte ipProto = packet.get();
+ short ipChksm = packet.getShort();
+
+ ipSrc = readIpAddress(packet);
+ ipDst = readIpAddress(packet);
+
+ if (ipProto != IP_TYPE_UDP) {
+ throw new ParseException(
+ DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
+ }
+
+ // Skip options. This cannot cause us to read beyond the end of the buffer because the
+ // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
+ // MIN_PACKET_LENGTH_L3.
+ int optionWords = ((ipTypeAndLength & 0x0f) - 5);
+ for (int i = 0; i < optionWords; i++) {
+ packet.getInt();
+ }
+
+ // assume UDP
+ short udpSrcPort = packet.getShort();
+ short udpDstPort = packet.getShort();
+ short udpLen = packet.getShort();
+ short udpChkSum = packet.getShort();
+
+ // Only accept packets to or from the well-known client port (expressly permitting
+ // packets from ports other than the well-known server port; http://b/24687559), and
+ // server-to-server packets, e.g. for relays.
+ if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
+ !isPacketServerToServer(udpSrcPort, udpDstPort)) {
+ // This should almost never happen because we use SO_ATTACH_FILTER on the packet
+ // socket to drop packets that don't have the right source ports. However, it's
+ // possible that a packet arrives between when the socket is bound and when the
+ // filter is set. http://b/26696823 .
+ throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
+ "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
+ }
+ }
+
+ // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
+ if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+ throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
+ "Invalid type or BOOTP packet too short, %d < %d",
+ packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
+ }
+
+ byte type = packet.get();
+ byte hwType = packet.get();
+ int addrLen = packet.get() & 0xff;
+ byte hops = packet.get();
+ transactionId = packet.getInt();
+ secs = packet.getShort();
+ short bootpFlags = packet.getShort();
+ boolean broadcast = (bootpFlags & 0x8000) != 0;
+ byte[] ipv4addr = new byte[4];
+
+ try {
+ packet.get(ipv4addr);
+ clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+ packet.get(ipv4addr);
+ yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+ packet.get(ipv4addr);
+ nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+ packet.get(ipv4addr);
+ relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+ } catch (UnknownHostException ex) {
+ throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
+ "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
+ }
+
+ // Some DHCP servers have been known to announce invalid client hardware address values such
+ // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
+ // all but only checks that the interface MAC address matches the first bytes of the address
+ // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
+ // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
+ // TODO: evaluate whether to make this test more liberal.
+ if (addrLen > HWADDR_LEN) {
+ addrLen = ETHER_BROADCAST.length;
+ }
+
+ clientMac = new byte[addrLen];
+ packet.get(clientMac);
+
+ // skip over address padding (16 octets allocated)
+ packet.position(packet.position() + (16 - addrLen));
+ serverHostName = readAsciiString(packet, 64, false);
+ packet.position(packet.position() + 128);
+
+ // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
+ if (packet.remaining() < 4) {
+ throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
+ }
+
+ int dhcpMagicCookie = packet.getInt();
+ if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+ throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
+ "Bad magic cookie 0x%08x, should be 0x%08x",
+ dhcpMagicCookie, DHCP_MAGIC_COOKIE);
+ }
+
+ // parse options
+ boolean notFinishedOptions = true;
+
+ while ((packet.position() < packet.limit()) && notFinishedOptions) {
+ final byte optionType = packet.get(); // cannot underflow because position < limit
+ try {
+ if (optionType == DHCP_OPTION_END) {
+ notFinishedOptions = false;
+ } else if (optionType == DHCP_OPTION_PAD) {
+ // The pad option doesn't have a length field. Nothing to do.
+ } else {
+ int optionLen = packet.get() & 0xFF;
+ int expectedLen = 0;
+
+ switch(optionType) {
+ case DHCP_SUBNET_MASK:
+ netMask = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_ROUTER:
+ for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+ gateways.add(readIpAddress(packet));
+ }
+ break;
+ case DHCP_DNS_SERVER:
+ for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+ dnsServers.add(readIpAddress(packet));
+ }
+ break;
+ case DHCP_HOST_NAME:
+ expectedLen = optionLen;
+ hostName = readAsciiString(packet, optionLen, false);
+ break;
+ case DHCP_MTU:
+ expectedLen = 2;
+ mtu = packet.getShort();
+ break;
+ case DHCP_DOMAIN_NAME:
+ expectedLen = optionLen;
+ domainName = readAsciiString(packet, optionLen, false);
+ break;
+ case DHCP_BROADCAST_ADDRESS:
+ bcAddr = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_REQUESTED_IP:
+ requestedIp = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_LEASE_TIME:
+ leaseTime = Integer.valueOf(packet.getInt());
+ expectedLen = 4;
+ break;
+ case DHCP_MESSAGE_TYPE:
+ dhcpType = packet.get();
+ expectedLen = 1;
+ break;
+ case DHCP_SERVER_IDENTIFIER:
+ serverIdentifier = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_PARAMETER_LIST:
+ expectedParams = new byte[optionLen];
+ packet.get(expectedParams);
+ expectedLen = optionLen;
+ break;
+ case DHCP_MESSAGE:
+ expectedLen = optionLen;
+ message = readAsciiString(packet, optionLen, false);
+ break;
+ case DHCP_MAX_MESSAGE_SIZE:
+ expectedLen = 2;
+ maxMessageSize = Short.valueOf(packet.getShort());
+ break;
+ case DHCP_RENEWAL_TIME:
+ expectedLen = 4;
+ T1 = Integer.valueOf(packet.getInt());
+ break;
+ case DHCP_REBINDING_TIME:
+ expectedLen = 4;
+ T2 = Integer.valueOf(packet.getInt());
+ break;
+ case DHCP_VENDOR_CLASS_ID:
+ expectedLen = optionLen;
+ // Embedded nulls are safe as this does not get passed to netd.
+ vendorId = readAsciiString(packet, optionLen, true);
+ break;
+ case DHCP_CLIENT_IDENTIFIER: { // Client identifier
+ byte[] id = new byte[optionLen];
+ packet.get(id);
+ expectedLen = optionLen;
+ } break;
+ case DHCP_VENDOR_INFO:
+ expectedLen = optionLen;
+ // Embedded nulls are safe as this does not get passed to netd.
+ vendorInfo = readAsciiString(packet, optionLen, true);
+ break;
+ case DHCP_OPTION_OVERLOAD:
+ expectedLen = 1;
+ optionOverload = packet.get();
+ optionOverload &= OPTION_OVERLOAD_BOTH;
+ break;
+ default:
+ // ignore any other parameters
+ for (int i = 0; i < optionLen; i++) {
+ expectedLen++;
+ byte throwaway = packet.get();
+ }
+ }
+
+ if (expectedLen != optionLen) {
+ final int errorCode = DhcpErrorEvent.errorCodeWithOption(
+ DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
+ throw new ParseException(errorCode,
+ "Invalid length %d for option %d, expected %d",
+ optionLen, optionType, expectedLen);
+ }
+ }
+ } catch (BufferUnderflowException e) {
+ final int errorCode = DhcpErrorEvent.errorCodeWithOption(
+ DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
+ throw new ParseException(errorCode, "BufferUnderflowException");
+ }
+ }
+
+ DhcpPacket newPacket;
+
+ switch(dhcpType) {
+ case (byte) 0xFF:
+ throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
+ "No DHCP message type option");
+ case DHCP_MESSAGE_TYPE_DISCOVER:
+ newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
+ broadcast, ipSrc);
+ break;
+ case DHCP_MESSAGE_TYPE_OFFER:
+ newPacket = new DhcpOfferPacket(
+ transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
+ break;
+ case DHCP_MESSAGE_TYPE_REQUEST:
+ newPacket = new DhcpRequestPacket(
+ transactionId, secs, clientIp, relayIp, clientMac, broadcast);
+ break;
+ case DHCP_MESSAGE_TYPE_DECLINE:
+ newPacket = new DhcpDeclinePacket(
+ transactionId, secs, clientIp, yourIp, nextIp, relayIp,
+ clientMac);
+ break;
+ case DHCP_MESSAGE_TYPE_ACK:
+ newPacket = new DhcpAckPacket(
+ transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
+ break;
+ case DHCP_MESSAGE_TYPE_NAK:
+ newPacket = new DhcpNakPacket(
+ transactionId, secs, relayIp, clientMac, broadcast);
+ break;
+ case DHCP_MESSAGE_TYPE_RELEASE:
+ if (serverIdentifier == null) {
+ throw new ParseException(DhcpErrorEvent.MISC_ERROR,
+ "DHCPRELEASE without server identifier");
+ }
+ newPacket = new DhcpReleasePacket(
+ transactionId, serverIdentifier, clientIp, relayIp, clientMac);
+ break;
+ case DHCP_MESSAGE_TYPE_INFORM:
+ newPacket = new DhcpInformPacket(
+ transactionId, secs, clientIp, yourIp, nextIp, relayIp,
+ clientMac);
+ break;
+ default:
+ throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
+ "Unimplemented DHCP type %d", dhcpType);
+ }
+
+ newPacket.mBroadcastAddress = bcAddr;
+ newPacket.mClientId = clientId;
+ newPacket.mDnsServers = dnsServers;
+ newPacket.mDomainName = domainName;
+ newPacket.mGateways = gateways;
+ newPacket.mHostName = hostName;
+ newPacket.mLeaseTime = leaseTime;
+ newPacket.mMessage = message;
+ newPacket.mMtu = mtu;
+ newPacket.mRequestedIp = requestedIp;
+ newPacket.mRequestedParams = expectedParams;
+ newPacket.mServerIdentifier = serverIdentifier;
+ newPacket.mSubnetMask = netMask;
+ newPacket.mMaxMessageSize = maxMessageSize;
+ newPacket.mT1 = T1;
+ newPacket.mT2 = T2;
+ newPacket.mVendorId = vendorId;
+ newPacket.mVendorInfo = vendorInfo;
+ if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
+ newPacket.mServerHostName = serverHostName;
+ } else {
+ newPacket.mServerHostName = "";
+ }
+ return newPacket;
+ }
+
+ /**
+ * Parse a packet from an array of bytes, stopping at the given length.
+ */
+ public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
+ throws ParseException {
+ ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
+ try {
+ return decodeFullPacket(buffer, pktType);
+ } catch (ParseException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * Construct a DhcpResults object from a DHCP reply packet.
+ */
+ public DhcpResults toDhcpResults() {
+ Inet4Address ipAddress = mYourIp;
+ if (ipAddress.equals(IPV4_ADDR_ANY)) {
+ ipAddress = mClientIp;
+ if (ipAddress.equals(IPV4_ADDR_ANY)) {
+ return null;
+ }
+ }
+
+ int prefixLength;
+ if (mSubnetMask != null) {
+ try {
+ prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask);
+ } catch (IllegalArgumentException e) {
+ // Non-contiguous netmask.
+ return null;
+ }
+ } else {
+ prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress);
+ }
+
+ DhcpResults results = new DhcpResults();
+ try {
+ results.ipAddress = new LinkAddress(ipAddress, prefixLength);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ if (mGateways.size() > 0) {
+ results.gateway = mGateways.get(0);
+ }
+
+ results.dnsServers.addAll(mDnsServers);
+ results.domains = mDomainName;
+ results.serverAddress = mServerIdentifier;
+ results.vendorInfo = mVendorInfo;
+ results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+ results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+ results.serverHostName = mServerHostName;
+
+ return results;
+ }
+
+ /**
+ * Returns the parsed lease time, in milliseconds, or 0 for infinite.
+ */
+ public long getLeaseTimeMillis() {
+ // dhcpcd treats the lack of a lease time option as an infinite lease.
+ if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
+ return 0;
+ } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
+ return MINIMUM_LEASE * 1000;
+ } else {
+ return (mLeaseTime & 0xffffffffL) * 1000;
+ }
+ }
+
+ /**
+ * Builds a DHCP-DISCOVER packet from the required specified
+ * parameters.
+ */
+ public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
+ short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
+ return buildDiscoverPacket(encap, transactionId, secs, clientMac,
+ broadcast, expectedParams, false);
+ }
+ public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
+ short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams,
+ boolean rapidCommit) {
+ DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, clientMac, broadcast, rapidCommit);
+ pkt.mRequestedParams = expectedParams;
+ return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
+ }
+
+ /**
+ * Builds a DHCP-OFFER packet from the required specified
+ * parameters.
+ */
+ public static ByteBuffer buildOfferPacket(int encap, int transactionId,
+ boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
+ Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
+ Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
+ Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+ short mtu) {
+ DhcpPacket pkt = new DhcpOfferPacket(
+ transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
+ INADDR_ANY /* clientIp */, yourIp, mac);
+ pkt.mGateways = gateways;
+ pkt.mDnsServers = dnsServers;
+ pkt.mLeaseTime = timeout;
+ pkt.mDomainName = domainName;
+ pkt.mHostName = hostname;
+ pkt.mServerIdentifier = dhcpServerIdentifier;
+ pkt.mSubnetMask = netMask;
+ pkt.mBroadcastAddress = bcAddr;
+ pkt.mMtu = mtu;
+ if (metered) {
+ pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+ }
+ return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+ }
+
+ /**
+ * Builds a DHCP-ACK packet from the required specified parameters.
+ */
+ public static ByteBuffer buildAckPacket(int encap, int transactionId,
+ boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
+ Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
+ Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
+ Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+ short mtu) {
+ DhcpPacket pkt = new DhcpAckPacket(
+ transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
+ mac);
+ pkt.mGateways = gateways;
+ pkt.mDnsServers = dnsServers;
+ pkt.mLeaseTime = timeout;
+ pkt.mDomainName = domainName;
+ pkt.mHostName = hostname;
+ pkt.mSubnetMask = netMask;
+ pkt.mServerIdentifier = dhcpServerIdentifier;
+ pkt.mBroadcastAddress = bcAddr;
+ pkt.mMtu = mtu;
+ if (metered) {
+ pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+ }
+ return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+ }
+
+ /**
+ * Builds a DHCP-NAK packet from the required specified parameters.
+ */
+ public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
+ Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
+ DhcpPacket pkt = new DhcpNakPacket(
+ transactionId, (short) 0, relayIp, mac, broadcast);
+ pkt.mMessage = message;
+ pkt.mServerIdentifier = serverIpAddr;
+ return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+ }
+
+ /**
+ * Builds a DHCP-REQUEST packet from the required specified parameters.
+ */
+ public static ByteBuffer buildRequestPacket(int encap,
+ int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
+ byte[] clientMac, Inet4Address requestedIpAddress,
+ Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
+ DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
+ INADDR_ANY /* relayIp */, clientMac, broadcast);
+ pkt.mRequestedIp = requestedIpAddress;
+ pkt.mServerIdentifier = serverIdentifier;
+ pkt.mHostName = hostName;
+ pkt.mRequestedParams = requestedParams;
+ ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
+ return result;
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
new file mode 100644
index 0000000..e37b0d3
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -0,0 +1,1795 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
+
+import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.DhcpResults;
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
+import android.net.NetworkStackIpMemoryStore;
+import android.net.ProvisioningConfigurationParcelable;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.TcpKeepalivePacketDataParcelable;
+import android.net.apf.ApfCapabilities;
+import android.net.apf.ApfFilter;
+import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpManagerEvent;
+import android.net.shared.InitialConfiguration;
+import android.net.shared.ProvisioningConfiguration;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IState;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
+import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService.NetworkStackServiceManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.nio.ByteBuffer;
+
+
+/**
+ * IpClient
+ *
+ * This class provides the interface to IP-layer provisioning and maintenance
+ * functionality that can be used by transport layers like Wi-Fi, Ethernet,
+ * et cetera.
+ *
+ * [ Lifetime ]
+ * IpClient is designed to be instantiated as soon as the interface name is
+ * known and can be as long-lived as the class containing it (i.e. declaring
+ * it "private final" is okay).
+ *
+ * @hide
+ */
+public class IpClient extends StateMachine {
+ private static final boolean DBG = false;
+
+ // For message logging.
+ private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
+ private static final SparseArray<String> sWhatToString =
+ MessageUtils.findMessageNames(sMessageClasses);
+ // Two static concurrent hashmaps of interface name to logging classes.
+ // One holds StateMachine logs and the other connectivity packet logs.
+ private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
+ private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+ private final NetworkStackIpMemoryStore mIpMemoryStore;
+
+ /**
+ * Dump all state machine and connectivity packet logs to the specified writer.
+ * @param skippedIfaces Interfaces for which logs should not be dumped.
+ */
+ public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
+ for (String ifname : sSmLogs.keySet()) {
+ if (skippedIfaces.contains(ifname)) continue;
+
+ writer.println(String.format("--- BEGIN %s ---", ifname));
+
+ final SharedLog smLog = sSmLogs.get(ifname);
+ if (smLog != null) {
+ writer.println("State machine log:");
+ smLog.dump(null, writer, null);
+ }
+
+ writer.println("");
+
+ final LocalLog pktLog = sPktLogs.get(ifname);
+ if (pktLog != null) {
+ writer.println("Connectivity packet log:");
+ pktLog.readOnlyLocalLog().dump(null, writer, null);
+ }
+
+ writer.println(String.format("--- END %s ---", ifname));
+ }
+ }
+
+ // Use a wrapper class to log in order to ensure complete and detailed
+ // logging. This method is lighter weight than annotations/reflection
+ // and has the following benefits:
+ //
+ // - No invoked method can be forgotten.
+ // Any new method added to IpClient.Callback must be overridden
+ // here or it will never be called.
+ //
+ // - No invoking call site can be forgotten.
+ // Centralized logging in this way means call sites don't need to
+ // remember to log, and therefore no call site can be forgotten.
+ //
+ // - No variation in log format among call sites.
+ // Encourages logging of any available arguments, and all call sites
+ // are necessarily logged identically.
+ //
+ // NOTE: Log first because passed objects may or may not be thread-safe and
+ // once passed on to the callback they may be modified by another thread.
+ //
+ // TODO: Find an lighter weight approach.
+ public static class IpClientCallbacksWrapper {
+ private static final String PREFIX = "INVOKE ";
+ private final IIpClientCallbacks mCallback;
+ private final SharedLog mLog;
+
+ @VisibleForTesting
+ protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log) {
+ mCallback = callback;
+ mLog = log;
+ }
+
+ private void log(String msg) {
+ mLog.log(PREFIX + msg);
+ }
+
+ private void log(String msg, Throwable e) {
+ mLog.e(PREFIX + msg, e);
+ }
+
+ public void onPreDhcpAction() {
+ log("onPreDhcpAction()");
+ try {
+ mCallback.onPreDhcpAction();
+ } catch (RemoteException e) {
+ log("Failed to call onPreDhcpAction", e);
+ }
+ }
+
+ public void onPostDhcpAction() {
+ log("onPostDhcpAction()");
+ try {
+ mCallback.onPostDhcpAction();
+ } catch (RemoteException e) {
+ log("Failed to call onPostDhcpAction", e);
+ }
+ }
+
+ public void onNewDhcpResults(DhcpResults dhcpResults) {
+ log("onNewDhcpResults({" + dhcpResults + "})");
+ try {
+ mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
+ } catch (RemoteException e) {
+ log("Failed to call onNewDhcpResults", e);
+ }
+ }
+
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ log("onProvisioningSuccess({" + newLp + "})");
+ try {
+ mCallback.onProvisioningSuccess(newLp);
+ } catch (RemoteException e) {
+ log("Failed to call onProvisioningSuccess", e);
+ }
+ }
+
+ public void onProvisioningFailure(LinkProperties newLp) {
+ log("onProvisioningFailure({" + newLp + "})");
+ try {
+ mCallback.onProvisioningFailure(newLp);
+ } catch (RemoteException e) {
+ log("Failed to call onProvisioningFailure", e);
+ }
+ }
+
+ public void onLinkPropertiesChange(LinkProperties newLp) {
+ log("onLinkPropertiesChange({" + newLp + "})");
+ try {
+ mCallback.onLinkPropertiesChange(newLp);
+ } catch (RemoteException e) {
+ log("Failed to call onLinkPropertiesChange", e);
+ }
+ }
+
+ public void onReachabilityLost(String logMsg) {
+ log("onReachabilityLost(" + logMsg + ")");
+ try {
+ mCallback.onReachabilityLost(logMsg);
+ } catch (RemoteException e) {
+ log("Failed to call onReachabilityLost", e);
+ }
+ }
+
+ public void onQuit() {
+ log("onQuit()");
+ try {
+ mCallback.onQuit();
+ } catch (RemoteException e) {
+ log("Failed to call onQuit", e);
+ }
+ }
+
+ public void installPacketFilter(byte[] filter) {
+ log("installPacketFilter(byte[" + filter.length + "])");
+ try {
+ mCallback.installPacketFilter(filter);
+ } catch (RemoteException e) {
+ log("Failed to call installPacketFilter", e);
+ }
+ }
+
+ public void startReadPacketFilter() {
+ log("startReadPacketFilter()");
+ try {
+ mCallback.startReadPacketFilter();
+ } catch (RemoteException e) {
+ log("Failed to call startReadPacketFilter", e);
+ }
+ }
+
+ public void setFallbackMulticastFilter(boolean enabled) {
+ log("setFallbackMulticastFilter(" + enabled + ")");
+ try {
+ mCallback.setFallbackMulticastFilter(enabled);
+ } catch (RemoteException e) {
+ log("Failed to call setFallbackMulticastFilter", e);
+ }
+ }
+
+ public void setNeighborDiscoveryOffload(boolean enable) {
+ log("setNeighborDiscoveryOffload(" + enable + ")");
+ try {
+ mCallback.setNeighborDiscoveryOffload(enable);
+ } catch (RemoteException e) {
+ log("Failed to call setNeighborDiscoveryOffload", e);
+ }
+ }
+ }
+
+ public static final String DUMP_ARG_CONFIRM = "confirm";
+
+ // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
+ private static final int CMD_TERMINATE_AFTER_STOP = 1;
+ private static final int CMD_STOP = 2;
+ private static final int CMD_START = 3;
+ private static final int CMD_CONFIRM = 4;
+ private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 5;
+ // Triggered by NetlinkTracker to communicate netlink events.
+ private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
+ private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 7;
+ private static final int CMD_UPDATE_HTTP_PROXY = 8;
+ private static final int CMD_SET_MULTICAST_FILTER = 9;
+ private static final int EVENT_PROVISIONING_TIMEOUT = 10;
+ private static final int EVENT_DHCPACTION_TIMEOUT = 11;
+ private static final int EVENT_READ_PACKET_FILTER_COMPLETE = 12;
+ private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
+ private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
+ private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
+
+ // Internal commands to use instead of trying to call transitionTo() inside
+ // a given State's enter() method. Calling transitionTo() from enter/exit
+ // encounters a Log.wtf() that can cause trouble on eng builds.
+ private static final int CMD_JUMP_STARTED_TO_RUNNING = 100;
+ private static final int CMD_JUMP_RUNNING_TO_STOPPING = 101;
+ private static final int CMD_JUMP_STOPPING_TO_STOPPED = 102;
+
+ // IpClient shares a handler with DhcpClient: commands must not overlap
+ public static final int DHCPCLIENT_CMD_BASE = 1000;
+
+ private static final int MAX_LOG_RECORDS = 500;
+ private static final int MAX_PACKET_RECORDS = 100;
+
+ private static final boolean NO_CALLBACKS = false;
+ private static final boolean SEND_CALLBACKS = true;
+
+ // This must match the interface prefix in clatd.c.
+ // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
+ private static final String CLAT_PREFIX = "v4-";
+
+ private static final int IMMEDIATE_FAILURE_DURATION = 0;
+
+ private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
+ private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
+ private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
+ private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
+
+ private final State mStoppedState = new StoppedState();
+ private final State mStoppingState = new StoppingState();
+ private final State mStartedState = new StartedState();
+ private final State mRunningState = new RunningState();
+
+ private final String mTag;
+ private final Context mContext;
+ private final String mInterfaceName;
+ private final String mClatInterfaceName;
+ @VisibleForTesting
+ protected final IpClientCallbacksWrapper mCallback;
+ private final Dependencies mDependencies;
+ private final CountDownLatch mShutdownLatch;
+ private final ConnectivityManager mCm;
+ private final INetd mNetd;
+ private final NetworkObserverRegistry mObserverRegistry;
+ private final IpClientLinkObserver mLinkObserver;
+ private final WakeupMessage mProvisioningTimeoutAlarm;
+ private final WakeupMessage mDhcpActionTimeoutAlarm;
+ private final SharedLog mLog;
+ private final LocalLog mConnectivityPacketLog;
+ private final MessageHandlingLogger mMsgStateLogger;
+ private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+ private final InterfaceController mInterfaceCtrl;
+
+ private InterfaceParams mInterfaceParams;
+
+ /**
+ * Non-final member variables accessed only from within our StateMachine.
+ */
+ private LinkProperties mLinkProperties;
+ private android.net.shared.ProvisioningConfiguration mConfiguration;
+ private IpReachabilityMonitor mIpReachabilityMonitor;
+ private DhcpClient mDhcpClient;
+ private DhcpResults mDhcpResults;
+ private String mTcpBufferSizes;
+ private ProxyInfo mHttpProxy;
+ private ApfFilter mApfFilter;
+ private String mL2Key; // The L2 key for this network, for writing into the memory store
+ private String mGroupHint; // The group hint for this network, for writing into the memory store
+ private boolean mMulticastFiltering;
+ private long mStartTimeMillis;
+
+ /**
+ * Reading the snapshot is an asynchronous operation initiated by invoking
+ * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
+ * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
+ * signals when a new snapshot is ready.
+ */
+ private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
+
+ public static class Dependencies {
+ /**
+ * Get interface parameters for the specified interface.
+ */
+ public InterfaceParams getInterfaceParams(String ifname) {
+ return InterfaceParams.getByName(ifname);
+ }
+
+ /**
+ * Get a INetd connector.
+ */
+ public INetd getNetd(Context context) {
+ return INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
+ }
+ }
+
+ public IpClient(Context context, String ifName, IIpClientCallbacks callback,
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
+ this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
+ }
+
+ @VisibleForTesting
+ IpClient(Context context, String ifName, IIpClientCallbacks callback,
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
+ Dependencies deps) {
+ super(IpClient.class.getSimpleName() + "." + ifName);
+ Preconditions.checkNotNull(ifName);
+ Preconditions.checkNotNull(callback);
+
+ mTag = getName();
+
+ mContext = context;
+ mInterfaceName = ifName;
+ mClatInterfaceName = CLAT_PREFIX + ifName;
+ mDependencies = deps;
+ mShutdownLatch = new CountDownLatch(1);
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ mObserverRegistry = observerRegistry;
+ mIpMemoryStore =
+ new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
+
+ sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
+ mLog = sSmLogs.get(mInterfaceName);
+ sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
+ mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
+ mMsgStateLogger = new MessageHandlingLogger();
+ mCallback = new IpClientCallbacksWrapper(callback, mLog);
+
+ // TODO: Consider creating, constructing, and passing in some kind of
+ // InterfaceController.Dependencies class.
+ mNetd = deps.getNetd(mContext);
+ mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
+
+ mLinkObserver = new IpClientLinkObserver(
+ mInterfaceName,
+ () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
+ @Override
+ public void onInterfaceAdded(String iface) {
+ super.onInterfaceAdded(iface);
+ if (mClatInterfaceName.equals(iface)) {
+ mCallback.setNeighborDiscoveryOffload(false);
+ } else if (!mInterfaceName.equals(iface)) {
+ return;
+ }
+
+ final String msg = "interfaceAdded(" + iface + ")";
+ logMsg(msg);
+ }
+
+ @Override
+ public void onInterfaceRemoved(String iface) {
+ super.onInterfaceRemoved(iface);
+ // TODO: Also observe mInterfaceName going down and take some
+ // kind of appropriate action.
+ if (mClatInterfaceName.equals(iface)) {
+ // TODO: consider sending a message to the IpClient main
+ // StateMachine thread, in case "NDO enabled" state becomes
+ // tied to more things that 464xlat operation.
+ mCallback.setNeighborDiscoveryOffload(true);
+ } else if (!mInterfaceName.equals(iface)) {
+ return;
+ }
+
+ final String msg = "interfaceRemoved(" + iface + ")";
+ logMsg(msg);
+ }
+
+ private void logMsg(String msg) {
+ Log.d(mTag, msg);
+ getHandler().post(() -> mLog.log("OBSERVED " + msg));
+ }
+ };
+
+ mLinkProperties = new LinkProperties();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+
+ mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+ mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
+ mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+ mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
+
+ // Anything the StateMachine may access must have been instantiated
+ // before this point.
+ configureAndStartStateMachine();
+
+ // Anything that may send messages to the StateMachine must only be
+ // configured to do so after the StateMachine has started (above).
+ startStateMachineUpdaters();
+ }
+
+ /**
+ * Make a IIpClient connector to communicate with this IpClient.
+ */
+ public IIpClient makeConnector() {
+ return new IpClientConnector();
+ }
+
+ class IpClientConnector extends IIpClient.Stub {
+ @Override
+ public void completedPreDhcpAction() {
+ checkNetworkStackCallingPermission();
+ IpClient.this.completedPreDhcpAction();
+ }
+ @Override
+ public void confirmConfiguration() {
+ checkNetworkStackCallingPermission();
+ IpClient.this.confirmConfiguration();
+ }
+ @Override
+ public void readPacketFilterComplete(byte[] data) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.readPacketFilterComplete(data);
+ }
+ @Override
+ public void shutdown() {
+ checkNetworkStackCallingPermission();
+ IpClient.this.shutdown();
+ }
+ @Override
+ public void startProvisioning(ProvisioningConfigurationParcelable req) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
+ }
+ @Override
+ public void stop() {
+ checkNetworkStackCallingPermission();
+ IpClient.this.stop();
+ }
+ @Override
+ public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
+ }
+ @Override
+ public void setTcpBufferSizes(String tcpBufferSizes) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.setTcpBufferSizes(tcpBufferSizes);
+ }
+ @Override
+ public void setHttpProxy(ProxyInfo proxyInfo) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.setHttpProxy(proxyInfo);
+ }
+ @Override
+ public void setMulticastFilter(boolean enabled) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.setMulticastFilter(enabled);
+ }
+ @Override
+ public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.addKeepalivePacketFilter(slot, pkt);
+ }
+ @Override
+ public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
+ }
+ @Override
+ public void removeKeepalivePacketFilter(int slot) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.removeKeepalivePacketFilter(slot);
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ }
+
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
+ private void configureAndStartStateMachine() {
+ // CHECKSTYLE:OFF IndentationCheck
+ addState(mStoppedState);
+ addState(mStartedState);
+ addState(mRunningState, mStartedState);
+ addState(mStoppingState);
+ // CHECKSTYLE:ON IndentationCheck
+
+ setInitialState(mStoppedState);
+
+ super.start();
+ }
+
+ private void startStateMachineUpdaters() {
+ mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver);
+ }
+
+ private void stopStateMachineUpdaters() {
+ mObserverRegistry.unregisterObserver(mLinkObserver);
+ }
+
+ @Override
+ protected void onQuitting() {
+ mCallback.onQuit();
+ mShutdownLatch.countDown();
+ }
+
+ /**
+ * Shut down this IpClient instance altogether.
+ */
+ public void shutdown() {
+ stop();
+ sendMessage(CMD_TERMINATE_AFTER_STOP);
+ }
+
+ /**
+ * Start provisioning with the provided parameters.
+ */
+ public void startProvisioning(ProvisioningConfiguration req) {
+ if (!req.isValid()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+ return;
+ }
+
+ mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
+ if (mInterfaceParams == null) {
+ logError("Failed to find InterfaceParams for " + mInterfaceName);
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
+ return;
+ }
+
+ mCallback.setNeighborDiscoveryOffload(true);
+ sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
+ }
+
+ /**
+ * Stop this IpClient.
+ *
+ * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
+ */
+ public void stop() {
+ sendMessage(CMD_STOP);
+ }
+
+ /**
+ * Confirm the provisioning configuration.
+ */
+ public void confirmConfiguration() {
+ sendMessage(CMD_CONFIRM);
+ }
+
+ /**
+ * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
+ * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
+ * proceed.
+ */
+ public void completedPreDhcpAction() {
+ sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+ }
+
+ /**
+ * Indicate that packet filter read is complete.
+ */
+ public void readPacketFilterComplete(byte[] data) {
+ sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
+ }
+
+ /**
+ * Set the TCP buffer sizes to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setTcpBufferSizes(String tcpBufferSizes) {
+ sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+ }
+
+ /**
+ * Set the L2 key and group hint for storing info into the memory store.
+ */
+ public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+ sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
+ }
+
+ /**
+ * Set the HTTP Proxy configuration to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setHttpProxy(ProxyInfo proxyInfo) {
+ sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+ }
+
+ /**
+ * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering,
+ * if not, Callback.setFallbackMulticastFilter() is called.
+ */
+ public void setMulticastFilter(boolean enabled) {
+ sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+ }
+
+ /**
+ * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
+ * keepalive offload.
+ */
+ public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
+ }
+
+ /**
+ * Called by WifiStateMachine to add NATT keepalive packet filter before setting up
+ * keepalive offload.
+ */
+ public void addNattKeepalivePacketFilter(int slot,
+ @NonNull NattKeepalivePacketDataParcelable pkt) {
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */ , pkt);
+ }
+
+ /**
+ * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
+ * offload.
+ */
+ public void removeKeepalivePacketFilter(int slot) {
+ sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
+ }
+
+ /**
+ * Dump logs of this IpClient.
+ */
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
+ // Execute confirmConfiguration() and take no further action.
+ confirmConfiguration();
+ return;
+ }
+
+ // Thread-unsafe access to mApfFilter but just used for debugging.
+ final ApfFilter apfFilter = mApfFilter;
+ final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
+ final ApfCapabilities apfCapabilities = (provisioningConfig != null)
+ ? provisioningConfig.mApfCapabilities : null;
+
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println(mTag + " APF dump:");
+ pw.increaseIndent();
+ if (apfFilter != null) {
+ if (apfCapabilities.hasDataAccess()) {
+ // Request a new snapshot, then wait for it.
+ mApfDataSnapshotComplete.close();
+ mCallback.startReadPacketFilter();
+ if (!mApfDataSnapshotComplete.block(1000)) {
+ pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
+ }
+ }
+ apfFilter.dump(pw);
+
+ } else {
+ pw.print("No active ApfFilter; ");
+ if (provisioningConfig == null) {
+ pw.println("IpClient not yet started.");
+ } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
+ pw.println("Hardware does not support APF.");
+ } else {
+ pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
+ }
+ }
+ pw.decreaseIndent();
+ pw.println();
+ pw.println(mTag + " current ProvisioningConfiguration:");
+ pw.increaseIndent();
+ pw.println(Objects.toString(provisioningConfig, "N/A"));
+ pw.decreaseIndent();
+
+ final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
+ if (iprm != null) {
+ pw.println();
+ pw.println(mTag + " current IpReachabilityMonitor state:");
+ pw.increaseIndent();
+ iprm.dump(pw);
+ pw.decreaseIndent();
+ }
+
+ pw.println();
+ pw.println(mTag + " StateMachine dump:");
+ pw.increaseIndent();
+ mLog.dump(fd, pw, args);
+ pw.decreaseIndent();
+
+ pw.println();
+ pw.println(mTag + " connectivity packet log:");
+ pw.println();
+ pw.println("Debug with python and scapy via:");
+ pw.println("shell$ python");
+ pw.println(">>> from scapy import all as scapy");
+ pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
+ pw.println();
+
+ pw.increaseIndent();
+ mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
+ pw.decreaseIndent();
+ }
+
+
+ /**
+ * Internals.
+ */
+
+ @Override
+ protected String getWhatToString(int what) {
+ return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
+ }
+
+ @Override
+ protected String getLogRecString(Message msg) {
+ final String logLine = String.format(
+ "%s/%d %d %d %s [%s]",
+ mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
+ msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
+
+ final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
+ mLog.log(richerLogLine);
+ if (DBG) {
+ Log.d(mTag, richerLogLine);
+ }
+
+ mMsgStateLogger.reset();
+ return logLine;
+ }
+
+ @Override
+ protected boolean recordLogRec(Message msg) {
+ // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
+ // and we already log any LinkProperties change that results in an
+ // invocation of IpClient.Callback#onLinkPropertiesChange().
+ final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+ if (!shouldLog) {
+ mMsgStateLogger.reset();
+ }
+ return shouldLog;
+ }
+
+ private void logError(String fmt, Object... args) {
+ final String msg = "ERROR " + String.format(fmt, args);
+ Log.e(mTag, msg);
+ mLog.log(msg);
+ }
+
+ // This needs to be called with care to ensure that our LinkProperties
+ // are in sync with the actual LinkProperties of the interface. For example,
+ // we should only call this if we know for sure that there are no IP addresses
+ // assigned to the interface, etc.
+ private void resetLinkProperties() {
+ mLinkObserver.clearLinkProperties();
+ mConfiguration = null;
+ mDhcpResults = null;
+ mTcpBufferSizes = "";
+ mHttpProxy = null;
+
+ mLinkProperties = new LinkProperties();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+ }
+
+ private void recordMetric(final int type) {
+ // We may record error metrics prior to starting.
+ // Map this to IMMEDIATE_FAILURE_DURATION.
+ final long duration = (mStartTimeMillis > 0)
+ ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
+ : IMMEDIATE_FAILURE_DURATION;
+ mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
+ }
+
+ // For now: use WifiStateMachine's historical notion of provisioned.
+ @VisibleForTesting
+ static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
+ // For historical reasons, we should connect even if all we have is
+ // an IPv4 address and nothing else.
+ if (lp.hasIpv4Address() || lp.isProvisioned()) {
+ return true;
+ }
+ if (config == null) {
+ return false;
+ }
+
+ // When an InitialConfiguration is specified, ignore any difference with previous
+ // properties and instead check if properties observed match the desired properties.
+ return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
+ }
+
+ // TODO: Investigate folding all this into the existing static function
+ // LinkProperties.compareProvisioning() or some other single function that
+ // takes two LinkProperties objects and returns a ProvisioningChange
+ // object that is a correct and complete assessment of what changed, taking
+ // account of the asymmetries described in the comments in this function.
+ // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+ private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
+ int delta;
+ InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
+ final boolean wasProvisioned = isProvisioned(oldLp, config);
+ final boolean isProvisioned = isProvisioned(newLp, config);
+
+ if (!wasProvisioned && isProvisioned) {
+ delta = PROV_CHANGE_GAINED_PROVISIONING;
+ } else if (wasProvisioned && isProvisioned) {
+ delta = PROV_CHANGE_STILL_PROVISIONED;
+ } else if (!wasProvisioned && !isProvisioned) {
+ delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
+ } else {
+ // (wasProvisioned && !isProvisioned)
+ //
+ // Note that this is true even if we lose a configuration element
+ // (e.g., a default gateway) that would not be required to advance
+ // into provisioned state. This is intended: if we have a default
+ // router and we lose it, that's a sure sign of a problem, but if
+ // we connect to a network with no IPv4 DNS servers, we consider
+ // that to be a network without DNS servers and connect anyway.
+ //
+ // See the comment below.
+ delta = PROV_CHANGE_LOST_PROVISIONING;
+ }
+
+ final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
+ final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
+ final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
+
+ // If bad wifi avoidance is disabled, then ignore IPv6 loss of
+ // provisioning. Otherwise, when a hotspot that loses Internet
+ // access sends out a 0-lifetime RA to its clients, the clients
+ // will disconnect and then reconnect, avoiding the bad hotspot,
+ // instead of getting stuck on the bad hotspot. http://b/31827713 .
+ //
+ // This is incorrect because if the hotspot then regains Internet
+ // access with a different prefix, TCP connections on the
+ // deprecated addresses will remain stuck.
+ //
+ // Note that we can still be disconnected by IpReachabilityMonitor
+ // if the IPv6 default gateway (but not the IPv6 DNS servers; see
+ // accompanying code in IpReachabilityMonitor) is unreachable.
+ final boolean ignoreIPv6ProvisioningLoss =
+ mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
+ && mCm.shouldAvoidBadWifi();
+
+ // Additionally:
+ //
+ // Partial configurations (e.g., only an IPv4 address with no DNS
+ // servers and no default route) are accepted as long as DHCPv4
+ // succeeds. On such a network, isProvisioned() will always return
+ // false, because the configuration is not complete, but we want to
+ // connect anyway. It might be a disconnected network such as a
+ // Chromecast or a wireless printer, for example.
+ //
+ // Because on such a network isProvisioned() will always return false,
+ // delta will never be LOST_PROVISIONING. So check for loss of
+ // provisioning here too.
+ if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
+ delta = PROV_CHANGE_LOST_PROVISIONING;
+ }
+
+ // Additionally:
+ //
+ // If the previous link properties had a global IPv6 address and an
+ // IPv6 default route then also consider the loss of that default route
+ // to be a loss of provisioning. See b/27962810.
+ if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
+ delta = PROV_CHANGE_LOST_PROVISIONING;
+ }
+
+ return delta;
+ }
+
+ private void dispatchCallback(int delta, LinkProperties newLp) {
+ switch (delta) {
+ case PROV_CHANGE_GAINED_PROVISIONING:
+ if (DBG) {
+ Log.d(mTag, "onProvisioningSuccess()");
+ }
+ recordMetric(IpManagerEvent.PROVISIONING_OK);
+ mCallback.onProvisioningSuccess(newLp);
+ break;
+
+ case PROV_CHANGE_LOST_PROVISIONING:
+ if (DBG) {
+ Log.d(mTag, "onProvisioningFailure()");
+ }
+ recordMetric(IpManagerEvent.PROVISIONING_FAIL);
+ mCallback.onProvisioningFailure(newLp);
+ break;
+
+ default:
+ if (DBG) {
+ Log.d(mTag, "onLinkPropertiesChange()");
+ }
+ mCallback.onLinkPropertiesChange(newLp);
+ break;
+ }
+ }
+
+ // Updates all IpClient-related state concerned with LinkProperties.
+ // Returns a ProvisioningChange for possibly notifying other interested
+ // parties that are not fronted by IpClient.
+ private int setLinkProperties(LinkProperties newLp) {
+ if (mApfFilter != null) {
+ mApfFilter.setLinkProperties(newLp);
+ }
+ if (mIpReachabilityMonitor != null) {
+ mIpReachabilityMonitor.updateLinkProperties(newLp);
+ }
+
+ int delta = compareProvisioning(mLinkProperties, newLp);
+ mLinkProperties = new LinkProperties(newLp);
+
+ if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
+ // TODO: Add a proper ProvisionedState and cancel the alarm in
+ // its enter() method.
+ mProvisioningTimeoutAlarm.cancel();
+ }
+
+ return delta;
+ }
+
+ private LinkProperties assembleLinkProperties() {
+ // [1] Create a new LinkProperties object to populate.
+ LinkProperties newLp = new LinkProperties();
+ newLp.setInterfaceName(mInterfaceName);
+
+ // [2] Pull in data from netlink:
+ // - IPv4 addresses
+ // - IPv6 addresses
+ // - IPv6 routes
+ // - IPv6 DNS servers
+ //
+ // N.B.: this is fundamentally race-prone and should be fixed by
+ // changing IpClientLinkObserver from a hybrid edge/level model to an
+ // edge-only model, or by giving IpClient its own netlink socket(s)
+ // so as to track all required information directly.
+ LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
+ newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
+ for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
+ newLp.addRoute(route);
+ }
+ addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
+
+ // [3] Add in data from DHCPv4, if available.
+ //
+ // mDhcpResults is never shared with any other owner so we don't have
+ // to worry about concurrent modification.
+ if (mDhcpResults != null) {
+ final List<RouteInfo> routes =
+ mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
+ for (RouteInfo route : routes) {
+ newLp.addRoute(route);
+ }
+ addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
+ newLp.setDomains(mDhcpResults.domains);
+
+ if (mDhcpResults.mtu != 0) {
+ newLp.setMtu(mDhcpResults.mtu);
+ }
+ }
+
+ // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+ if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+ newLp.setTcpBufferSizes(mTcpBufferSizes);
+ }
+ if (mHttpProxy != null) {
+ newLp.setHttpProxy(mHttpProxy);
+ }
+
+ // [5] Add data from InitialConfiguration
+ if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
+ InitialConfiguration config = mConfiguration.mInitialConfig;
+ // Add InitialConfiguration routes and dns server addresses once all addresses
+ // specified in the InitialConfiguration have been observed with Netlink.
+ if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
+ for (IpPrefix prefix : config.directlyConnectedRoutes) {
+ newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST));
+ }
+ }
+ addAllReachableDnsServers(newLp, config.dnsServers);
+ }
+ final LinkProperties oldLp = mLinkProperties;
+ if (DBG) {
+ Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
+ netlinkLinkProperties, newLp, oldLp));
+ }
+
+ // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
+ // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
+ return newLp;
+ }
+
+ private static void addAllReachableDnsServers(
+ LinkProperties lp, Iterable<InetAddress> dnses) {
+ // TODO: Investigate deleting this reachability check. We should be
+ // able to pass everything down to netd and let netd do evaluation
+ // and RFC6724-style sorting.
+ for (InetAddress dns : dnses) {
+ if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
+ lp.addDnsServer(dns);
+ }
+ }
+ }
+
+ // Returns false if we have lost provisioning, true otherwise.
+ private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+ final LinkProperties newLp = assembleLinkProperties();
+ if (Objects.equals(newLp, mLinkProperties)) {
+ return true;
+ }
+ final int delta = setLinkProperties(newLp);
+ // Most of the attributes stored in the memory store are deduced from
+ // the link properties, therefore when the properties update the memory
+ // store record should be updated too.
+ maybeSaveNetworkToIpMemoryStore();
+ if (sendCallbacks) {
+ dispatchCallback(delta, newLp);
+ }
+ return (delta != PROV_CHANGE_LOST_PROVISIONING);
+ }
+
+ private void handleIPv4Success(DhcpResults dhcpResults) {
+ mDhcpResults = new DhcpResults(dhcpResults);
+ final LinkProperties newLp = assembleLinkProperties();
+ final int delta = setLinkProperties(newLp);
+
+ if (DBG) {
+ Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+ }
+ mCallback.onNewDhcpResults(dhcpResults);
+ maybeSaveNetworkToIpMemoryStore();
+ dispatchCallback(delta, newLp);
+ }
+
+ private void handleIPv4Failure() {
+ // TODO: Investigate deleting this clearIPv4Address() call.
+ //
+ // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
+ // that could trigger a call to this function. If we missed handling
+ // that message in StartedState for some reason we would still clear
+ // any addresses upon entry to StoppedState.
+ mInterfaceCtrl.clearIPv4Address();
+ mDhcpResults = null;
+ if (DBG) {
+ Log.d(mTag, "onNewDhcpResults(null)");
+ }
+ mCallback.onNewDhcpResults(null);
+
+ handleProvisioningFailure();
+ }
+
+ private void handleProvisioningFailure() {
+ final LinkProperties newLp = assembleLinkProperties();
+ int delta = setLinkProperties(newLp);
+ // If we've gotten here and we're still not provisioned treat that as
+ // a total loss of provisioning.
+ //
+ // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+ // there was no usable IPv6 obtained before a non-zero provisioning
+ // timeout expired.
+ //
+ // Regardless: GAME OVER.
+ if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
+ delta = PROV_CHANGE_LOST_PROVISIONING;
+ }
+
+ dispatchCallback(delta, newLp);
+ if (delta == PROV_CHANGE_LOST_PROVISIONING) {
+ transitionTo(mStoppingState);
+ }
+ }
+
+ private void doImmediateProvisioningFailure(int failureType) {
+ logError("onProvisioningFailure(): %s", failureType);
+ recordMetric(failureType);
+ mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
+ }
+
+ private boolean startIPv4() {
+ // If we have a StaticIpConfiguration attempt to apply it and
+ // handle the result accordingly.
+ if (mConfiguration.mStaticIpConfig != null) {
+ if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
+ handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
+ } else {
+ return false;
+ }
+ } else {
+ // Start DHCPv4.
+ mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
+ mDhcpClient.registerForPreDhcpNotification();
+ if (mConfiguration.mRapidCommit || mConfiguration.mDiscoverSent)
+ mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP_RAPID_COMMIT,
+ (mConfiguration.mRapidCommit ? 1: 0),
+ (mConfiguration.mDiscoverSent ? 1: 0));
+ else
+ mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
+ }
+
+ return true;
+ }
+
+ private boolean startIPv6() {
+ return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
+ && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
+ && mInterfaceCtrl.enableIPv6();
+ }
+
+ private boolean applyInitialConfig(InitialConfiguration config) {
+ // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
+ for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
+ if (!mInterfaceCtrl.addAddress(addr)) return false;
+ }
+
+ return true;
+ }
+
+ private boolean startIpReachabilityMonitor() {
+ try {
+ // TODO: Fetch these parameters from settings, and install a
+ // settings observer to watch for update and re-program these
+ // parameters (Q: is this level of dynamic updatability really
+ // necessary or does reading from settings at startup suffice?).
+ final int numSolicits = 5;
+ final int interSolicitIntervalMs = 750;
+ setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs);
+ } catch (Exception e) {
+ mLog.e("Failed to adjust neighbor parameters", e);
+ // Carry on using the system defaults (currently: 3, 1000);
+ }
+
+ try {
+ mIpReachabilityMonitor = new IpReachabilityMonitor(
+ mContext,
+ mInterfaceParams,
+ getHandler(),
+ mLog,
+ new IpReachabilityMonitor.Callback() {
+ @Override
+ public void notifyLost(InetAddress ip, String logMsg) {
+ mCallback.onReachabilityLost(logMsg);
+ }
+ },
+ mConfiguration.mUsingMultinetworkPolicyTracker);
+ } catch (IllegalArgumentException iae) {
+ // Failed to start IpReachabilityMonitor. Log it and call
+ // onProvisioningFailure() immediately.
+ //
+ // See http://b/31038971.
+ logError("IpReachabilityMonitor failure: %s", iae);
+ mIpReachabilityMonitor = null;
+ }
+
+ return (mIpReachabilityMonitor != null);
+ }
+
+
+ public ByteBuffer buildDiscoverWithRapidCommitPacket() {
+ return mDhcpClient.buildDiscoverWithRapidCommitPacket();
+ }
+
+ private void stopAllIP() {
+ // We don't need to worry about routes, just addresses, because:
+ // - disableIpv6() will clear autoconf IPv6 routes as well, and
+ // - we don't get IPv4 routes from netlink
+ // so we neither react to nor need to wait for changes in either.
+
+ mInterfaceCtrl.disableIPv6();
+ mInterfaceCtrl.clearAllAddresses();
+ }
+
+ private void maybeSaveNetworkToIpMemoryStore() {
+ // TODO : implement this
+ }
+
+ class StoppedState extends State {
+ @Override
+ public void enter() {
+ stopAllIP();
+
+ resetLinkProperties();
+ if (mStartTimeMillis > 0) {
+ // Completed a life-cycle; send a final empty LinkProperties
+ // (cleared in resetLinkProperties() above) and record an event.
+ mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
+ recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
+ mStartTimeMillis = 0;
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_TERMINATE_AFTER_STOP:
+ stopStateMachineUpdaters();
+ quit();
+ break;
+
+ case CMD_STOP:
+ break;
+
+ case CMD_START:
+ mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
+ transitionTo(mStartedState);
+ break;
+
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_L2KEY_GROUPHINT: {
+ final Pair<String, String> args = (Pair<String, String>) msg.obj;
+ mL2Key = args.first;
+ mGroupHint = args.second;
+ break;
+ }
+
+ case CMD_SET_MULTICAST_FILTER:
+ mMulticastFiltering = (boolean) msg.obj;
+ break;
+
+ case DhcpClient.CMD_ON_QUIT:
+ // Everything is already stopped.
+ logError("Unexpected CMD_ON_QUIT (already stopped).");
+ break;
+
+ default:
+ return NOT_HANDLED;
+ }
+
+ mMsgStateLogger.handled(this, getCurrentState());
+ return HANDLED;
+ }
+ }
+
+ class StoppingState extends State {
+ @Override
+ public void enter() {
+ if (mDhcpClient == null) {
+ // There's no DHCPv4 for which to wait; proceed to stopped.
+ deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_JUMP_STOPPING_TO_STOPPED:
+ transitionTo(mStoppedState);
+ break;
+
+ case CMD_STOP:
+ break;
+
+ case DhcpClient.CMD_CLEAR_LINKADDRESS:
+ mInterfaceCtrl.clearIPv4Address();
+ break;
+
+ case DhcpClient.CMD_ON_QUIT:
+ mDhcpClient = null;
+ transitionTo(mStoppedState);
+ break;
+
+ default:
+ deferMessage(msg);
+ }
+
+ mMsgStateLogger.handled(this, getCurrentState());
+ return HANDLED;
+ }
+ }
+
+ class StartedState extends State {
+ @Override
+ public void enter() {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+
+ if (mConfiguration.mProvisioningTimeoutMs > 0) {
+ final long alarmTime = SystemClock.elapsedRealtime()
+ + mConfiguration.mProvisioningTimeoutMs;
+ mProvisioningTimeoutAlarm.schedule(alarmTime);
+ }
+
+ if (readyToProceed()) {
+ deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
+ } else {
+ // Clear all IPv4 and IPv6 before proceeding to RunningState.
+ // Clean up any leftover state from an abnormal exit from
+ // tethering or during an IpClient restart.
+ stopAllIP();
+ }
+ }
+
+ @Override
+ public void exit() {
+ mProvisioningTimeoutAlarm.cancel();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_JUMP_STARTED_TO_RUNNING:
+ transitionTo(mRunningState);
+ break;
+
+ case CMD_STOP:
+ transitionTo(mStoppingState);
+ break;
+
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ if (readyToProceed()) {
+ transitionTo(mRunningState);
+ }
+ break;
+
+ case CMD_UPDATE_L2KEY_GROUPHINT: {
+ final Pair<String, String> args = (Pair<String, String>) msg.obj;
+ mL2Key = args.first;
+ mGroupHint = args.second;
+ // TODO : attributes should be saved to the memory store with
+ // these new values if they differ from the previous ones.
+ // If the state machine is in pure StartedState, then the values to input
+ // are not known yet and should be updated when the LinkProperties are updated.
+ // If the state machine is in RunningState (which is a child of StartedState)
+ // then the next NUD check should be used to store the new values to avoid
+ // inputting current values for what may be a different L3 network.
+ break;
+ }
+
+ case EVENT_PROVISIONING_TIMEOUT:
+ handleProvisioningFailure();
+ break;
+
+ default:
+ // It's safe to process messages out of order because the
+ // only message that can both
+ // a) be received at this time and
+ // b) affect provisioning state
+ // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+ deferMessage(msg);
+ }
+
+ mMsgStateLogger.handled(this, getCurrentState());
+ return HANDLED;
+ }
+
+ private boolean readyToProceed() {
+ return (!mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address());
+ }
+ }
+
+ class RunningState extends State {
+ private ConnectivityPacketTracker mPacketTracker;
+ private boolean mDhcpActionInFlight;
+
+ @Override
+ public void enter() {
+ ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
+ apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
+ apfConfig.multicastFilter = mMulticastFiltering;
+ // Get the Configuration for ApfFilter from Context
+ apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
+ apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
+ mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
+ // TODO: investigate the effects of any multicast filtering racing/interfering with the
+ // rest of this IP configuration startup.
+ if (mApfFilter == null) {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+
+ mPacketTracker = createPacketTracker();
+ if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
+
+ if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+ enqueueJumpToStoppingState();
+ return;
+ }
+
+ if (mConfiguration.mEnableIPv4 && !startIPv4()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
+ enqueueJumpToStoppingState();
+ return;
+ }
+
+ final InitialConfiguration config = mConfiguration.mInitialConfig;
+ if ((config != null) && !applyInitialConfig(config)) {
+ // TODO introduce a new IpManagerEvent constant to distinguish this error case.
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+ enqueueJumpToStoppingState();
+ return;
+ }
+
+ if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
+ doImmediateProvisioningFailure(
+ IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
+ enqueueJumpToStoppingState();
+ return;
+ }
+ }
+
+ @Override
+ public void exit() {
+ stopDhcpAction();
+
+ if (mIpReachabilityMonitor != null) {
+ mIpReachabilityMonitor.stop();
+ mIpReachabilityMonitor = null;
+ }
+
+ if (mDhcpClient != null) {
+ mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+ mDhcpClient.doQuit();
+ }
+
+ if (mPacketTracker != null) {
+ mPacketTracker.stop();
+ mPacketTracker = null;
+ }
+
+ if (mApfFilter != null) {
+ mApfFilter.shutdown();
+ mApfFilter = null;
+ }
+
+ resetLinkProperties();
+ }
+
+ private void enqueueJumpToStoppingState() {
+ deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
+ }
+
+ private ConnectivityPacketTracker createPacketTracker() {
+ try {
+ return new ConnectivityPacketTracker(
+ getHandler(), mInterfaceParams, mConnectivityPacketLog);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ private void ensureDhcpAction() {
+ if (!mDhcpActionInFlight) {
+ mCallback.onPreDhcpAction();
+ mDhcpActionInFlight = true;
+ final long alarmTime = SystemClock.elapsedRealtime()
+ + mConfiguration.mRequestedPreDhcpActionMs;
+ mDhcpActionTimeoutAlarm.schedule(alarmTime);
+ }
+ }
+
+ private void stopDhcpAction() {
+ mDhcpActionTimeoutAlarm.cancel();
+ if (mDhcpActionInFlight) {
+ mCallback.onPostDhcpAction();
+ mDhcpActionInFlight = false;
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_JUMP_RUNNING_TO_STOPPING:
+ case CMD_STOP:
+ transitionTo(mStoppingState);
+ break;
+
+ case CMD_START:
+ logError("ALERT: START received in StartedState. Please fix caller.");
+ break;
+
+ case CMD_CONFIRM:
+ // TODO: Possibly introduce a second type of confirmation
+ // that both probes (a) on-link neighbors and (b) does
+ // a DHCPv4 RENEW. We used to do this on Wi-Fi framework
+ // roams.
+ if (mIpReachabilityMonitor != null) {
+ mIpReachabilityMonitor.probeAll();
+ }
+ break;
+
+ case EVENT_PRE_DHCP_ACTION_COMPLETE:
+ // It's possible to reach here if, for example, someone
+ // calls completedPreDhcpAction() after provisioning with
+ // a static IP configuration.
+ if (mDhcpClient != null) {
+ mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
+ }
+ break;
+
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
+ transitionTo(mStoppingState);
+ }
+ break;
+
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
+ break;
+
+ case CMD_SET_MULTICAST_FILTER: {
+ mMulticastFiltering = (boolean) msg.obj;
+ if (mApfFilter != null) {
+ mApfFilter.setMulticastFilter(mMulticastFiltering);
+ } else {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+ break;
+ }
+
+ case EVENT_READ_PACKET_FILTER_COMPLETE: {
+ if (mApfFilter != null) {
+ mApfFilter.setDataSnapshot((byte[]) msg.obj);
+ }
+ mApfDataSnapshotComplete.open();
+ break;
+ }
+
+ case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
+ final int slot = msg.arg1;
+
+ if (mApfFilter != null) {
+ if (msg.obj instanceof NattKeepalivePacketDataParcelable) {
+ mApfFilter.addNattKeepalivePacketFilter(slot,
+ (NattKeepalivePacketDataParcelable) msg.obj);
+ } else if (msg.obj instanceof TcpKeepalivePacketDataParcelable) {
+ mApfFilter.addTcpKeepalivePacketFilter(slot,
+ (TcpKeepalivePacketDataParcelable) msg.obj);
+ }
+ }
+ break;
+ }
+
+ case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
+ final int slot = msg.arg1;
+ if (mApfFilter != null) {
+ mApfFilter.removeKeepalivePacketFilter(slot);
+ }
+ break;
+ }
+
+ case EVENT_DHCPACTION_TIMEOUT:
+ stopDhcpAction();
+ break;
+
+ case DhcpClient.CMD_PRE_DHCP_ACTION:
+ if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
+ ensureDhcpAction();
+ } else {
+ sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+ }
+ break;
+
+ case DhcpClient.CMD_CLEAR_LINKADDRESS:
+ mInterfaceCtrl.clearIPv4Address();
+ break;
+
+ case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
+ final LinkAddress ipAddress = (LinkAddress) msg.obj;
+ if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
+ mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
+ } else {
+ logError("Failed to set IPv4 address.");
+ dispatchCallback(PROV_CHANGE_LOST_PROVISIONING,
+ new LinkProperties(mLinkProperties));
+ transitionTo(mStoppingState);
+ }
+ break;
+ }
+
+ // This message is only received when:
+ //
+ // a) initial address acquisition succeeds,
+ // b) renew succeeds or is NAK'd,
+ // c) rebind succeeds or is NAK'd, or
+ // c) the lease expires,
+ //
+ // but never when initial address acquisition fails. The latter
+ // condition is now governed by the provisioning timeout.
+ case DhcpClient.CMD_POST_DHCP_ACTION:
+ stopDhcpAction();
+
+ switch (msg.arg1) {
+ case DhcpClient.DHCP_SUCCESS:
+ handleIPv4Success((DhcpResults) msg.obj);
+ break;
+ case DhcpClient.DHCP_FAILURE:
+ handleIPv4Failure();
+ break;
+ default:
+ logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
+ }
+ break;
+
+ case DhcpClient.CMD_ON_QUIT:
+ // DHCPv4 quit early for some reason.
+ logError("Unexpected CMD_ON_QUIT.");
+ mDhcpClient = null;
+ break;
+
+ default:
+ return NOT_HANDLED;
+ }
+
+ mMsgStateLogger.handled(this, getCurrentState());
+ return HANDLED;
+ }
+ }
+
+ private static class MessageHandlingLogger {
+ public String processedInState;
+ public String receivedInState;
+
+ public void reset() {
+ processedInState = null;
+ receivedInState = null;
+ }
+
+ public void handled(State processedIn, IState receivedIn) {
+ processedInState = processedIn.getClass().getSimpleName();
+ receivedInState = receivedIn.getName();
+ }
+
+ public String toString() {
+ return String.format("rcvd_in=%s, proc_in=%s",
+ receivedInState, processedInState);
+ }
+ }
+
+ private static void setNeighborParameters(
+ INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs)
+ throws RemoteException, IllegalArgumentException {
+ Preconditions.checkNotNull(netd);
+ Preconditions.checkArgument(!TextUtils.isEmpty(ifName));
+ Preconditions.checkArgument(numSolicits > 0);
+ Preconditions.checkArgument(interSolicitIntervalMs > 0);
+
+ for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) {
+ netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms",
+ Integer.toString(interSolicitIntervalMs));
+ netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit",
+ Integer.toString(numSolicits));
+ }
+ }
+
+ // TODO: extract out into CollectionUtils.
+ static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
+ for (T t : coll) {
+ if (fn.test(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
+ return !any(coll, not(fn));
+ }
+
+ static <T> Predicate<T> not(Predicate<T> fn) {
+ return (t) -> !fn.test(t);
+ }
+
+ static <T> String join(String delimiter, Collection<T> coll) {
+ return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
+ }
+
+ static <T> T find(Iterable<T> coll, Predicate<T> fn) {
+ for (T t: coll) {
+ if (fn.test(t)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
+ return coll.stream().filter(fn).collect(Collectors.toList());
+ }
+}
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index c48f62b..171a2dc 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"Disabled"</item>
<item msgid="1969681323976948639">"Enabled Filtered"</item>
<item msgid="8719029132154020716">"Enabled"</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index c48f62b..171a2dc 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"Disabled"</item>
<item msgid="1969681323976948639">"Enabled Filtered"</item>
<item msgid="8719029132154020716">"Enabled"</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index c48f62b..8ab7d21 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"Disabled"</item>
<item msgid="1969681323976948639">"Enabled Filtered"</item>
<item msgid="8719029132154020716">"Enabled"</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
@@ -82,6 +84,8 @@
<item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
<item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
<item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="8711430979086781450">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_ADAPTIVE">aptX™ Adaptive</xliff:g> audio"</item>
+ <item msgid="6486050771049225">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_TWSP">aptX™ TWS+</xliff:g> audio"</item>
<item msgid="723675059572222462">"Enable Optional Codecs"</item>
<item msgid="3304843301758635896">"Disable Optional Codecs"</item>
</string-array>
@@ -92,6 +96,8 @@
<item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
<item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
<item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="102988075927343894">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_ADAPTIVE">aptX™ Adaptive</xliff:g> audio"</item>
+ <item msgid="6486050771049481">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_TWSP">aptX™ TWS+</xliff:g> audio"</item>
<item msgid="2209680154067241740">"Enable Optional Codecs"</item>
<item msgid="741805482892725657">"Disable Optional Codecs"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index c48f62b..171a2dc 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"Disabled"</item>
<item msgid="1969681323976948639">"Enabled Filtered"</item>
<item msgid="8719029132154020716">"Enabled"</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
diff --git a/packages/SettingsLib/res/values-en-rXC/arrays.xml b/packages/SettingsLib/res/values-en-rXC/arrays.xml
index 90594fd..f7fb201 100644
--- a/packages/SettingsLib/res/values-en-rXC/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rXC/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"Disabled"</item>
<item msgid="1969681323976948639">"Enabled Filtered"</item>
<item msgid="8719029132154020716">"Enabled"</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (Default)"</item>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 2de8c86..d9fc620 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"無効"</item>
<item msgid="1969681323976948639">"有効(フィルタ済み)"</item>
<item msgid="8719029132154020716">"有効"</item>
+ <item>"有効(ヘッダーのみ)"</item>
+ <item>"有効(メディアパケット除外)"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4(デフォルト)"</item>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index 15e11db..ec9cb57 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"사용 중지됨"</item>
<item msgid="1969681323976948639">"필터링 사용 설정됨"</item>
<item msgid="8719029132154020716">"사용 설정됨"</item>
+ <item>"헤더 필터링 사용 설정됨"</item>
+ <item>"미디어 패킷 필터링 사용 설정됨"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4(기본)"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 2706823..fdad8fc 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"已停用"</item>
<item msgid="1969681323976948639">"已启用“已过滤”"</item>
<item msgid="8719029132154020716">"已启用"</item>
+ <item>"已过滤已启用的标题"</item>
+ <item>"已过滤已启用的媒体包"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4(默认)"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 8872cc96..7c202d1 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"已停用"</item>
<item msgid="1969681323976948639">"已啟用篩選"</item>
<item msgid="8719029132154020716">"已啟用"</item>
+ <item>"已過濾已啟用的標題"</item>
+ <item>"已過濾已啟用的媒體包"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (預設)"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 37e095e..4abd03c 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -62,6 +62,8 @@
<item msgid="3966341281672645384">"已停用"</item>
<item msgid="1969681323976948639">"已啟用篩選結果"</item>
<item msgid="8719029132154020716">"已啟用"</item>
+ <item>"已過濾已啟用的標題"</item>
+ <item>"已過濾已啟用的媒體包"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (預設)"</item>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 39c55fd..de9beb4 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -107,6 +107,8 @@
<item>Disabled</item>
<item>Enabled Filtered</item>
<item>Enabled</item>
+ <item>Enabled Headers Filtered</item>
+ <item>Enabled Media Pkts Filtered</item>
</string-array>
<!-- Values for Bluetooth HCI Snoop Logging -->
@@ -114,6 +116,8 @@
<item>disabled</item>
<item>filtered</item>
<item>full</item>
+ <item>snoopheadersfiltered</item>
+ <item>mediapktsfiltered</item>
</string-array>
<!-- Titles for Bluetooth AVRCP Versions -->
@@ -140,6 +144,8 @@
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
<item>LDAC</item>
+ <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_adaptive">aptX™ Adaptive</xliff:g> audio</item>
+ <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_twsp">aptX™ TWS+</xliff:g> audio</item>
<item>Enable Optional Codecs</item>
<item>Disable Optional Codecs</item>
</string-array>
@@ -154,6 +160,8 @@
<item>4</item>
<item>5</item>
<item>6</item>
+ <item>7</item>
+ <item>8</item>
</string-array>
<!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
@@ -164,6 +172,8 @@
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx">aptX™</xliff:g> audio</item>
<item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_hd">aptX™ HD</xliff:g> audio</item>
<item>LDAC</item>
+ <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_adaptive">aptX™ Adaptive</xliff:g> audio</item>
+ <item><xliff:g id="qualcomm">Qualcomm®</xliff:g> <xliff:g id="aptx_twsp">aptX™ TWS+</xliff:g> audio</item>
<item>Enable Optional Codecs</item>
<item>Disable Optional Codecs</item>
</string-array>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a855741..df4484c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -36,6 +36,8 @@
<string name="wifi_security_short_eap_wpa" translatable="false">WPA-EAP</string>
<!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_short_eap_wpa2_wpa3" translatable="false">RSN-EAP</string>
+ <!-- Do not translate. Concise terminology for wifi with DPP security -->
+ <string name="wifi_security_short_dpp" translatable="false">DPP</string>
<!-- Do not translate. Concise terminology for wifi with WPA3 security -->
<string name="wifi_security_short_sae" translatable="false">WPA3</string>
<!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 transition security -->
@@ -66,6 +68,8 @@
<string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
<!-- Do not translate. Concise terminology for Passpoint network -->
<string name="wifi_security_passpoint" translatable="false">Passpoint</string>
+ <!-- Do not translate. Concise terminology for DPP network -->
+ <string name="wifi_security_dpp" translatable="false">DPP</string>
<!-- Do not translate. Terminology for wifi with WPA3 security -->
<string name="wifi_security_sae" translatable="false">WPA3-Personal</string>
<!-- Do not translate. Terminology for wifi with WPA2/WPA3 Transition mode security -->
@@ -234,6 +238,8 @@
<string name="bluetooth_profile_map">Text Messages</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the SAP profile (sharing SIM card). -->
<string name="bluetooth_profile_sap">SIM Access</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the dun profile. -->
+ <string name="bluetooth_profile_dun">Dial-up Network Access</string>
<!-- Bluetooth settings. The user-visible string for the setting controlling whether to use a high-quality codec if the device supports it, along with the name of the codec (eg AAC, LDAC, aptX) -->
<string name="bluetooth_profile_a2dp_high_quality">HD audio: <xliff:g id="codec_name">%1$s</xliff:g></string>
@@ -264,6 +270,8 @@
<string name="bluetooth_pan_user_profile_summary_connected">Connected to device for internet access</string>
<!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (NAP role). [CHAR LIMIT=25]-->
<string name="bluetooth_pan_nap_profile_summary_connected">Sharing local internet connection with device</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the DUN checkbox preference when DUN is connected. -->
+ <string name="bluetooth_dun_profile_summary_connected">Connected to Dun Server</string>
<!-- Bluetooth settings. Connection options screen. The summary
for the PAN checkbox preference that describes how checking it
@@ -285,6 +293,8 @@
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
<string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aids</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the dun checkbox preference that describes how checking it will set the dun profile as preferred. -->
+ <string name="bluetooth_dun_profile_summary_use_for">Use for Dial-up Network access</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
@@ -579,6 +589,8 @@
<!-- Setting Checkbox title whether to show options for wireless display certification -->
<string name="wifi_display_certification">Wireless display certification</string>
+ <!-- Setting Checkbox title whether to enable WiFi coverage extending feature. -->
+ <string name="wifi_coverage_extend">Enable Wi\u2011Fi Coverage Extend Feature</string>
<!-- Setting Checkbox title whether to enable WiFi Verbose Logging. [CHAR LIMIT=40] -->
<string name="wifi_verbose_logging">Enable Wi\u2011Fi Verbose Logging</string>
<!-- Setting Checkbox title whether to disable WiFi Scan Throttling. [CHAR LIMIT=40] -->
@@ -637,6 +649,9 @@
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
<!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR_LIMIT=NONE] -->
+ <!-- Setting Checkbox summary whether to enable WiFi coverage extending feature. -->
+ <string name="wifi_coverage_extend_summary">Enable extending Wi\u2011Fi coverage using Hotspot</string>
+ <!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
<string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string>
<!-- Setting Checkbox summary whether to disable Wifi scan throttling [CHAR LIMIT=NONE] -->
<string name="wifi_scan_throttling_summary">Reduces battery drain & improves network performance</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 14f233d..3c677bd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -52,6 +52,30 @@
com.android.internal.R.drawable.ic_wifi_signal_4
};
+ static final int[] WIFI_4_PIE = {
+ com.android.internal.R.drawable.ic_wifi_4_signal_0,
+ com.android.internal.R.drawable.ic_wifi_4_signal_1,
+ com.android.internal.R.drawable.ic_wifi_4_signal_2,
+ com.android.internal.R.drawable.ic_wifi_4_signal_3,
+ com.android.internal.R.drawable.ic_wifi_4_signal_4
+ };
+
+ static final int[] WIFI_5_PIE = {
+ com.android.internal.R.drawable.ic_wifi_5_signal_0,
+ com.android.internal.R.drawable.ic_wifi_5_signal_1,
+ com.android.internal.R.drawable.ic_wifi_5_signal_2,
+ com.android.internal.R.drawable.ic_wifi_5_signal_3,
+ com.android.internal.R.drawable.ic_wifi_5_signal_4
+ };
+
+ static final int[] WIFI_6_PIE = {
+ com.android.internal.R.drawable.ic_wifi_6_signal_0,
+ com.android.internal.R.drawable.ic_wifi_6_signal_1,
+ com.android.internal.R.drawable.ic_wifi_6_signal_2,
+ com.android.internal.R.drawable.ic_wifi_6_signal_3,
+ com.android.internal.R.drawable.ic_wifi_6_signal_4
+ };
+
public static void updateLocationEnabled(Context context, boolean enabled, int userId,
int source) {
Settings.Secure.putIntForUser(
@@ -322,10 +346,34 @@
* @throws IllegalArgumentException if an invalid RSSI level is given.
*/
public static int getWifiIconResource(int level) {
+ return getWifiIconResource(level, 0 /* generation */, false /* isReady */);
+ }
+
+ /**
+ * Returns the Wifi icon resource for a given RSSI level.
+ *
+ * @param level The number of bars to show (0-4)
+ * @throws IllegalArgumentException if an invalid RSSI level is given.
+ */
+ public static int getWifiIconResource(int level, int generation, boolean isReady) {
if (level < 0 || level >= WIFI_PIE.length) {
throw new IllegalArgumentException("No Wifi icon found for level: " + level);
}
- return WIFI_PIE[level];
+
+ switch (generation) {
+ case 4:
+ return WIFI_4_PIE[level];
+ case 5:
+ if (isReady) {
+ return WIFI_6_PIE[level];
+ } else {
+ return WIFI_5_PIE[level];
+ }
+ case 6:
+ return WIFI_6_PIE[level];
+ default:
+ return WIFI_PIE[level];
+ }
}
public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 785dd56..82de56e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -35,6 +35,7 @@
public class A2dpProfile implements LocalBluetoothProfile {
private static final String TAG = "A2dpProfile";
+ private static boolean V = true;
private Context mContext;
@@ -210,11 +211,21 @@
}
public boolean supportsHighQualityAudio(BluetoothDevice device) {
+ if (V) Log.d(TAG, " execute supportsHighQualityAudio()");
+ if (mService == null) {
+ if (V) Log.d(TAG,"mService is null.");
+ return false;
+ }
int support = mService.supportsOptionalCodecs(device);
return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
}
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
+ if (V) Log.d(TAG, " execute isHighQualityAudioEnabled()");
+ if (mService == null) {
+ if (V) Log.d(TAG,"mService is null.");
+ return false;
+ }
int enabled = mService.getOptionalCodecsEnabled(device);
if (enabled != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN) {
return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED;
@@ -237,9 +248,14 @@
}
public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
+ if (V) Log.d(TAG, " execute setHighQualityAudioEnabled()");
int prefValue = enabled
? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
: BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
+ if (mService == null) {
+ if (V) Log.d(TAG,"mService is null.");
+ return;
+ }
mService.setOptionalCodecsEnabled(device, prefValue);
if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
return;
@@ -252,6 +268,7 @@
}
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
+ if (V) Log.d(TAG, " execute getHighQualityAudioOptionLabel()");
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
if (!supportsHighQualityAudio(device)
|| getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
@@ -260,7 +277,7 @@
// We want to get the highest priority codec, since that's the one that will be used with
// this device, and see if it is high-quality (ie non-mandatory).
BluetoothCodecConfig[] selectable = null;
- if (mService.getCodecStatus(device) != null) {
+ if (mService != null && mService.getCodecStatus(device) != null) {
selectable = mService.getCodecStatus(device).getCodecsSelectableCapabilities();
// To get the highest priority, we sort in reverse.
Arrays.sort(selectable,
@@ -291,6 +308,12 @@
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
index = 5;
break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE:
+ index = 6;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP:
+ index = 7;
+ break;
}
if (index < 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index df30c24..6a85f4e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -108,6 +108,8 @@
addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
addHandler(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED, new BatteryLevelChangedHandler());
+ addHandler(BluetoothHeadset.ACTION_HF_TWSP_BATTERY_STATE_CHANGED ,
+ new TwspBatteryLevelChangedHandler());
// Active device broadcasts
addHandler(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler());
@@ -420,6 +422,24 @@
}
}
+ private class TwspBatteryLevelChangedHandler implements Handler {
+ public void onReceive(Context context, Intent intent,
+ BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+ if (cachedDevice != null) {
+ cachedDevice.mTwspBatteryState =
+ intent.getIntExtra(
+ BluetoothHeadset.EXTRA_HF_TWSP_BATTERY_STATE, -1);
+ cachedDevice.mTwspBatteryLevel =
+ intent.getIntExtra(
+ BluetoothHeadset.EXTRA_HF_TWSP_BATTERY_LEVEL, -1);
+ Log.i(TAG, cachedDevice + ": mTwspBatteryState: " + cachedDevice.mTwspBatteryState
+ + "mTwspBatteryLevel: " + cachedDevice.mTwspBatteryLevel);
+ cachedDevice.refresh();
+ }
+ }
+ }
+
private class ActiveDeviceChangedHandler implements Handler {
@Override
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 98db7c8..ec7b5ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -30,6 +30,7 @@
import android.util.EventLog;
import android.util.Log;
+import android.os.SystemProperties;
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.R;
@@ -55,6 +56,7 @@
// Some Hearing Aids (especially the 2nd device) needs more time to do service discovery
private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000;
private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+ private static final boolean mIsTwsConnectEnabled = false;
private final Context mContext;
private final BluetoothAdapter mLocalAdapter;
@@ -78,6 +80,8 @@
private final Collection<Callback> mCallbacks = new CopyOnWriteArrayList<>();
+ public int mTwspBatteryState;
+ public int mTwspBatteryLevel;
/**
* Last time a bt profile auto-connect was attempted.
* If an ACTION_UUID intent comes in within
@@ -101,6 +105,24 @@
mDevice = device;
fillData();
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ mTwspBatteryState = -1;
+ mTwspBatteryLevel = -1;
+ }
+
+ /* Gets Device for seondary TWS device
+ * @param mDevice Primary TWS device to get secondary
+ * @return Description of the device
+ */
+
+ private BluetoothDevice getTwsPeerDevice() {
+ BluetoothAdapter bluetoothAdapter;
+ BluetoothDevice peerDevice = null;
+ if (mDevice.isTwsPlusDevice()) {
+ bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ String peerAddress = mDevice.getTwsPlusPeerAddress();
+ peerDevice = bluetoothAdapter.getRemoteDevice(peerAddress);
+ }
+ return peerDevice;
}
/**
@@ -156,6 +178,10 @@
mProfiles.remove(profile);
mRemovedProfiles.add(profile);
mLocalNapRoleConnected = false;
+ } else if (profile instanceof HeadsetProfile
+ && newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
+ mTwspBatteryState = -1;
+ mTwspBatteryLevel = -1;
}
}
@@ -320,6 +346,17 @@
if (state != BluetoothDevice.BOND_NONE) {
final BluetoothDevice dev = mDevice;
+ if (mDevice.isTwsPlusDevice()) {
+ BluetoothDevice peerDevice = getTwsPeerDevice();
+ if (peerDevice != null) {
+ final boolean peersuccessful = peerDevice.removeBond();
+ if (peersuccessful) {
+ if (BluetoothUtils.D) {
+ Log.d(TAG, "Command sent successfully:REMOVE_BOND " + peerDevice.getName());
+ }
+ }
+ }
+ }
if (dev != null) {
final boolean successful = dev.removeBond();
if (successful) {
@@ -646,10 +683,20 @@
refresh();
if (bondState == BluetoothDevice.BOND_BONDED) {
+ boolean mIsBondingInitiatedLocally = mDevice.isBondingInitiatedLocally();
+ Log.w(TAG, "mIsBondingInitiatedLocally" + mIsBondingInitiatedLocally);
+ if (mIsBondingInitiatedLocally) {
+ mDevice.setBondingInitiatedLocally(false);
+ }
if (mDevice.isBluetoothDock()) {
onBondingDockConnect();
- } else if (mDevice.isBondingInitiatedLocally()) {
- connect(false);
+ } else if (mIsTwsConnectEnabled) {
+ Log.d(TAG, "Initiating connection to" + mDevice);
+ if (mIsBondingInitiatedLocally || mDevice.isTwsPlusDevice()) {
+ connect(false);
+ }
+ } else if (mIsBondingInitiatedLocally) {
+ connect(false);
}
}
}
@@ -796,10 +843,11 @@
// The pairing dialog now warns of phone-book access for paired devices.
// No separate prompt is displayed after pairing.
if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
- if (mDevice.getBluetoothClass().getDeviceClass()
+ if ((mDevice.getBluetoothClass() != null) &&
+ (mDevice.getBluetoothClass().getDeviceClass()
== BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE ||
mDevice.getBluetoothClass().getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) {
+ == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
EventLog.writeEvent(0x534e4554, "138529441", -1, "");
}
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
@@ -880,11 +928,28 @@
// BluetoothDevice.BATTERY_LEVEL_UNKNOWN, any other value should be a framework bug.
// Thus assume here that if value is not BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must
// be valid
- final int batteryLevel = getBatteryLevel();
- if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- // TODO: name com.android.settingslib.bluetooth.Utils something different
- batteryLevelPercentageString =
+
+ if (mDevice.isTwsPlusDevice() && mTwspBatteryState != -1 &&
+ mTwspBatteryLevel != -1) {
+ String s = "TWSP: ";
+ String chargingState;
+ if (mTwspBatteryState == 1) {
+ chargingState = "Charging, ";
+ } else {
+ chargingState = "Discharging, ";
+ }
+ s = s.concat (chargingState);
+ s = s.concat(
+ com.android.settingslib.Utils.formatPercentage(mTwspBatteryLevel));
+ batteryLevelPercentageString = s;
+ Log.i(TAG, "UI string" + batteryLevelPercentageString);
+ } else {
+ final int batteryLevel = getBatteryLevel();
+ if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ // TODO: name com.android.settingslib.bluetooth.Utils something different
+ batteryLevelPercentageString =
com.android.settingslib.Utils.formatPercentage(batteryLevel);
+ }
}
int stringRes = R.string.bluetooth_pairing;
@@ -1061,8 +1126,16 @@
*/
public boolean isConnectedA2dpDevice() {
A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
- return a2dpProfile != null && a2dpProfile.getConnectionStatus(mDevice) ==
+ A2dpSinkProfile a2dpSinkProfile = mProfileManager.getA2dpSinkProfile();
+ Log.i(TAG, "a2dpProfile :" + a2dpProfile + " a2dpSinkProfile :" + a2dpSinkProfile);
+ if (a2dpProfile != null) {
+ return a2dpProfile.getConnectionStatus(mDevice) ==
BluetoothProfile.STATE_CONNECTED;
+ } else if (a2dpSinkProfile != null) {
+ return a2dpSinkProfile.getConnectionStatus(mDevice) ==
+ BluetoothProfile.STATE_CONNECTED;
+ }
+ return false;
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index f243199..debb514 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -195,6 +195,13 @@
}
}
+ public synchronized void clearAllDevices() {
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ mCachedDevices.remove(i);
+ }
+ }
+
public synchronized void onScanningStateChanged(boolean started) {
if (!started) return;
// If starting a new scan, clear old visibility
@@ -225,6 +232,9 @@
cachedDevice.setJustDiscovered(false);
mCachedDevices.remove(i);
}
+ //Clear if there any Tws battery info on BT turning OFF
+ cachedDevice.mTwspBatteryState = -1;
+ cachedDevice.mTwspBatteryLevel = -1;
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java
new file mode 100644
index 0000000..013a443
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/DunServerProfile.java
@@ -0,0 +1,167 @@
+/*
+*Copyright (c) 2013, 2015, The Linux Foundation. All rights reserved.
+*
+*Redistribution and use in source and binary forms, with or without
+*modification, are permitted provided that the following conditions are
+*met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+*WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+*ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+*BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+*SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+*WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+*OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+*IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDun;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.List;
+
+import com.android.settingslib.R;
+
+/**
+ * DunServerProfile handles Bluetooth DUN server profile.
+ */
+public final class DunServerProfile implements LocalBluetoothProfile {
+ private static final String TAG = "DunServerProfile";
+ private static boolean V = true;
+
+ private BluetoothDun mService;
+ private boolean mIsProfileReady;
+
+ static final String NAME = "DUN Server";
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 11;
+
+ // These callbacks run on the main thread.
+ private final class DunServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (V) Log.d(TAG,"Bluetooth service connected");
+ mService = (BluetoothDun) proxy;
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (V) Log.d(TAG,"Bluetooth service disconnected");
+ mIsProfileReady = false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ @Override
+ public int getProfileId() {
+ return BluetoothProfile.DUN;
+ }
+
+ DunServerProfile(Context context) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ adapter.getProfileProxy(context, new DunServiceListener(),
+ BluetoothProfile.DUN);
+ }
+
+ public boolean accessProfileEnabled() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return false;
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) return false;
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean isPreferred(BluetoothDevice device) {
+ return true;
+ }
+
+ public int getPreferred(BluetoothDevice device) {
+ return -1;
+ }
+
+ public void setPreferred(BluetoothDevice device, boolean preferred) {
+ // ignore: isPreferred is always true for DUN
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_dun;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_dun_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_dun_profile_summary_connected;
+ default:
+ return BluetoothUtils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return com.android.internal.R.drawable.ic_bt_network_pan;
+ }
+
+ protected void finalize() {
+ if (V) Log.d(TAG, "finalize()");
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy
+ (BluetoothProfile.DUN, mService);
+ mService = null;
+ } catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up DUN proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 29c6d71..b18a6d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -30,6 +30,7 @@
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothPbap;
import android.bluetooth.BluetoothPbapClient;
+import android.bluetooth.BluetoothDun;
import android.bluetooth.BluetoothSap;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -47,6 +48,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import android.os.SystemProperties;
/**
@@ -97,6 +99,7 @@
private PanProfile mPanProfile;
private PbapClientProfile mPbapClientProfile;
private PbapServerProfile mPbapProfile;
+ private DunServerProfile mDunProfile;
private HearingAidProfile mHearingAidProfile;
private SapProfile mSapProfile;
@@ -218,6 +221,12 @@
mSapProfile = new SapProfile(mContext, mDeviceManager, this);
addProfile(mSapProfile, SapProfile.NAME, BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
}
+ if (mDunProfile == null && supportedList.contains(BluetoothProfile.DUN)) {
+ if(DEBUG) Log.d(TAG, "Adding local DUN profile");
+ mDunProfile = new DunServerProfile(mContext);
+ addProfile(mDunProfile, DunServerProfile.NAME,
+ BluetoothDun.ACTION_CONNECTION_STATE_CHANGED);
+ }
mEventManager.registerProfileIntentReceiver();
}
@@ -267,6 +276,11 @@
}
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+ if (device == null) {
+ Log.w(TAG, "StateChangedHandler receives state-change for invalid device");
+ return;
+ }
+
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
Log.w(TAG, "StateChangedHandler found new device: " + device);
@@ -474,7 +488,8 @@
if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
(BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
- BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+ BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) ||
+ (mHeadsetProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
profiles.add(mHeadsetProfile);
removedProfiles.remove(mHeadsetProfile);
}
@@ -487,10 +502,12 @@
removedProfiles.remove(mHfpClientProfile);
}
- if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
- mA2dpProfile != null) {
- profiles.add(mA2dpProfile);
- removedProfiles.remove(mA2dpProfile);
+ if (mA2dpProfile != null) {
+ if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) ||
+ (mA2dpProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
+ profiles.add(mA2dpProfile);
+ removedProfiles.remove(mA2dpProfile);
+ }
}
if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
index ff40d8e..8ad9cb8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
@@ -93,8 +93,7 @@
* {@link Message#what} value sent after the timeout waiting for a status message.
*/
private static final int WHAT_TIMEOUT = 3;
-
- private final Context mContext;
+ protected final Context mContext;
/**
* The settings that were injected
@@ -207,7 +206,7 @@
*
* Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
*/
- private static InjectedSetting parseServiceInfo(ResolveInfo service, UserHandle userHandle,
+ protected InjectedSetting parseServiceInfo(ResolveInfo service, UserHandle userHandle,
PackageManager pm) throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 16fd51f..8a0738d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -107,6 +107,16 @@
*/
public static final int HIGHER_FREQ_5GHZ = 5900;
+ /**
+ * Lower bound on the 60 GHz (802.11ad) WIGIG channels
+ */
+ public static final int LOWER_FREQ_60GHZ = 58320;
+
+ /**
+ * Upper bound on the 60 GHz (802.11ad) WIGIG channels
+ */
+ public static final int HIGHER_FREQ_60GHZ = 70200;
+
/** The key which identifies this AccessPoint grouping. */
private String mKey;
@@ -193,7 +203,8 @@
public static final int SECURITY_EAP_SUITE_B = 6;
public static final int SECURITY_PSK_SAE_TRANSITION = 7;
public static final int SECURITY_OWE_TRANSITION = 8;
- public static final int SECURITY_MAX_VAL = 9; // Has to be the last
+ public static final int SECURITY_DPP = 9;
+ public static final int SECURITY_MAX_VAL = 10; // Has to be the last
private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1;
@@ -205,6 +216,17 @@
private static final int EAP_WPA = 1; // WPA-EAP
private static final int EAP_WPA2_WPA3 = 2; // RSN-EAP
+ private static final int LEGACY_CAPABLE_BSSID = 0;
+ private static final int HT_CAPABLE_BSSID = 1;
+ private static final int VHT_CAPABLE_BSSID = 2;
+ private static final int HE_CAPABLE_BSSID = 3;
+ private static final int MAX_CAPABLE_BSSID = Integer.MAX_VALUE;
+
+ private static final int WIFI_GENERATION_LEGACY = 0;
+ private static final int WIFI_GENERATION_4 = 4;
+ private static final int WIFI_GENERATION_5 = 5;
+ private static final int WIFI_GENERATION_6 = 6;
+
/**
* The number of distinct wifi levels.
*
@@ -235,6 +257,10 @@
private int mRssi = UNREACHABLE_RSSI;
+ private int mWifiGeneration = WIFI_GENERATION_LEGACY;
+ private boolean mTwtSupport = false;
+ private boolean mVhtMax8SpatialStreamsSupport = false;
+
private WifiInfo mInfo;
private NetworkInfo mNetworkInfo;
AccessPointListener mAccessPointListener;
@@ -328,6 +354,7 @@
// Calculate required fields
updateKey();
updateBestRssiInfo();
+ updateWifiGeneration();
}
/**
@@ -748,6 +775,74 @@
networkId = WifiConfiguration.INVALID_NETWORK_ID;
}
+ public boolean isFils256Supported() {
+ IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ String capability = "";
+
+ try {
+ capability = wifiManager.getCapabilities("key_mgmt");
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote Exception", e);
+ }
+
+ if (!capability.contains("FILS-SHA256")) {
+ return false;
+ }
+
+ for (ScanResult result : mScanResults) {
+ if (result.capabilities.contains("FILS-SHA256")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSuiteBSupported() {
+ IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ String capability = "";
+
+ try {
+ capability = wifiManager.getCapabilities("key_mgmt");
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote Exception", e);
+ }
+
+ if (!capability.contains("WPA-EAP-SUITE-B-192")) {
+ return false;
+ }
+
+ for (ScanResult result : mScanResults) {
+ if (result.capabilities.contains("EAP_SUITE_B_192")) {
+ return true;
+ }
+ }
+ return false;
+ }
+ public boolean isFils384Supported() {
+ IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ String capability = "";
+
+ try {
+ capability = wifiManager.getCapabilities("key_mgmt");
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote Exception", e);
+ }
+
+ if (!capability.contains("FILS-SHA384")) {
+ return false;
+ }
+
+ for (ScanResult result : mScanResults) {
+ if (result.capabilities.contains("FILS-SHA384")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public WifiInfo getInfo() {
return mInfo;
}
@@ -837,6 +932,74 @@
}
}
+ private int getMaxCapability(ScanResult result) {
+ if (isVerboseLoggingEnabled()) {
+ Log.i(TAG, "SSID: "+ result.SSID +", bssid: "+ result.BSSID +", capabilities: "+ result.capabilities);
+ }
+
+ if (result.capabilities.contains("WFA-HE")) {
+ return HE_CAPABLE_BSSID;
+ } else if (result.capabilities.contains("WFA-VHT")) {
+ return VHT_CAPABLE_BSSID;
+ } else if (result.capabilities.contains("WFA-HT")) {
+ return HT_CAPABLE_BSSID;
+ } else {
+ return LEGACY_CAPABLE_BSSID;
+ }
+ }
+
+ /**
+ * Updates {@link #mWifiGeneration}.
+ *
+ * <p>If the given connection is active, the existing value of {@link #mWifiGeneration} will be returned.
+ * If the given AccessPoint is not active, a value will be calculated from previous scan
+ * results, based on minimum capability for all BSSIDs.
+ */
+ private void updateWifiGeneration() {
+ if (this.isActive()) {
+ return;
+ }
+
+ int currBssidMaxCapability;
+ int scanResultsMinCapability = MAX_CAPABLE_BSSID;
+
+ mTwtSupport = false;
+ mVhtMax8SpatialStreamsSupport = false;
+ for (ScanResult result : mScanResults) {
+ currBssidMaxCapability = getMaxCapability(result);
+ if (currBssidMaxCapability < scanResultsMinCapability) {
+ scanResultsMinCapability = currBssidMaxCapability;
+ }
+ }
+
+ switch (scanResultsMinCapability) {
+ case HE_CAPABLE_BSSID:
+ mWifiGeneration = WIFI_GENERATION_6;
+ break;
+ case VHT_CAPABLE_BSSID:
+ mWifiGeneration = WIFI_GENERATION_5;
+ break;
+ case HT_CAPABLE_BSSID:
+ mWifiGeneration = WIFI_GENERATION_4;
+ break;
+ default:
+ mWifiGeneration = WIFI_GENERATION_LEGACY;
+ break;
+ }
+ }
+
+ public int getWifiGeneration() {
+ return mWifiGeneration;
+ }
+
+ public boolean isTwtSupported() {
+ return mTwtSupport;
+ }
+
+ public boolean isVhtMax8SpatialStreamsSupported() {
+ return mVhtMax8SpatialStreamsSupport;
+ }
+
/**
* Returns if the network should be considered metered.
*/
@@ -897,6 +1060,9 @@
case SECURITY_WEP:
return concise ? context.getString(R.string.wifi_security_short_wep) :
context.getString(R.string.wifi_security_wep);
+ case SECURITY_DPP:
+ return concise ? context.getString(R.string.wifi_security_short_dpp) :
+ context.getString(R.string.wifi_security_dpp);
case SECURITY_SAE:
case SECURITY_PSK_SAE_TRANSITION:
if (pskType == PSK_SAE) {
@@ -1333,6 +1499,7 @@
mScanResults.addAll(scanResults);
}
updateBestRssiInfo();
+ updateWifiGeneration();
int newLevel = getLevel();
// If newLevel is 0, there will be no displayed Preference since the AP is unreachable
@@ -1400,6 +1567,14 @@
// are still seen, we will investigate further.
update(config); // Notifies the AccessPointListener of the change
}
+ if (mWifiGeneration != info.getWifiGeneration() ||
+ mTwtSupport != info.isTwtSupported() ||
+ mVhtMax8SpatialStreamsSupport != info.isVhtMax8SpatialStreamsSupported()) {
+ mWifiGeneration = info.getWifiGeneration();
+ mTwtSupport = info.isTwtSupported();
+ mVhtMax8SpatialStreamsSupport = info.isVhtMax8SpatialStreamsSupported();
+ updated = true;
+ }
if (mRssi != info.getRssi() && info.getRssi() != WifiInfo.INVALID_RSSI) {
mRssi = info.getRssi();
updated = true;
@@ -1413,6 +1588,7 @@
updated = true;
mInfo = null;
mNetworkInfo = null;
+ updateWifiGeneration();
}
if (updated && mAccessPointListener != null) {
ThreadUtils.postOnMainThread(() -> {
@@ -1600,7 +1776,8 @@
private static int getPskType(ScanResult result) {
boolean wpa = result.capabilities.contains("WPA-PSK");
boolean wpa2 = result.capabilities.contains("RSN-PSK");
- boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE");
+ boolean wpa3TransitionMode = result.capabilities.contains("PSK")
+ && result.capabilities.contains("SAE");
boolean wpa3 = result.capabilities.contains("RSN-SAE");
if (wpa3TransitionMode) {
return PSK_SAE;
@@ -1632,9 +1809,12 @@
}
private static int getSecurity(ScanResult result) {
- if (result.capabilities.contains("WEP")) {
+ if (result.capabilities.contains("DPP")) {
+ return SECURITY_DPP;
+ } else if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
- } else if (result.capabilities.contains("PSK+SAE")) {
+ } else if (result.capabilities.contains("PSK")
+ && result.capabilities.contains("SAE")) {
return SECURITY_PSK_SAE_TRANSITION;
} else if (result.capabilities.contains("SAE")) {
return SECURITY_SAE;
@@ -1666,6 +1846,9 @@
config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return SECURITY_EAP;
}
+ if (config.allowedKeyManagement.get(KeyMgmt.DPP)) {
+ return SECURITY_DPP;
+ }
if (config.allowedKeyManagement.get(KeyMgmt.OWE)) {
return SECURITY_OWE;
}
@@ -1686,6 +1869,8 @@
return "PSK";
} else if (security == SECURITY_EAP) {
return "EAP";
+ } else if (security == SECURITY_DPP) {
+ return "DPP";
} else if (security == SECURITY_SAE) {
return "SAE";
} else if (security == SECURITY_EAP_SUITE_B) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index dae5464..5e00c2e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -74,6 +74,9 @@
private AccessPoint mAccessPoint;
private Drawable mBadge;
private int mLevel;
+ private int mWifiGeneration;
+ private boolean mTwtSupport;
+ private boolean mVhtMax8SpatialStreamsSupport;
private CharSequence mContentDescription;
private int mDefaultIconResId;
private int mWifiSpeed = Speed.NONE;
@@ -174,14 +177,14 @@
notifyChanged();
}
- protected void updateIcon(int level, Context context) {
+ protected void updateIcon(int level, int generation, boolean isReady, Context context) {
if (level == -1) {
safeSetDefaultIcon();
return;
}
TronUtils.logWifiSettingsSpeed(context, mWifiSpeed);
- Drawable drawable = mIconInjector.getIcon(level);
+ Drawable drawable = mIconInjector.getIcon(level, generation, isReady);
if (!mForSavedNetworks && drawable != null) {
drawable.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal));
setIcon(drawable);
@@ -237,17 +240,36 @@
final Context context = getContext();
int level = mAccessPoint.getLevel();
int wifiSpeed = mAccessPoint.getSpeed();
- if (level != mLevel || wifiSpeed != mWifiSpeed) {
+ int wifiGeneration = mAccessPoint.getWifiGeneration();
+ boolean vhtMax8SpatialStreamsSupport = mAccessPoint.isVhtMax8SpatialStreamsSupported();
+ boolean twtSupport = mAccessPoint.isTwtSupported();
+
+ if (level != mLevel ||
+ wifiSpeed != mWifiSpeed ||
+ wifiGeneration != mWifiGeneration ||
+ mVhtMax8SpatialStreamsSupport != vhtMax8SpatialStreamsSupport ||
+ mTwtSupport != twtSupport) {
mLevel = level;
mWifiSpeed = wifiSpeed;
- updateIcon(mLevel, context);
+ mWifiGeneration = wifiGeneration;
+ mVhtMax8SpatialStreamsSupport = vhtMax8SpatialStreamsSupport;
+ mTwtSupport = twtSupport;
+ updateIcon(mLevel, mWifiGeneration, mVhtMax8SpatialStreamsSupport && mTwtSupport, context);
notifyChanged();
}
updateBadge(context);
- setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
- : mAccessPoint.getSettingsSummary());
+ String summary = mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
+ : mAccessPoint.getSettingsSummary();
+
+ if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_SAE) {
+ summary = "WPA3(SAE) " + summary;
+ } else if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE) {
+ summary = "WPA3(OWE) " + summary;
+ }
+
+ setSummary(summary);
mContentDescription = buildContentDescription(getContext(), this /* pref */, mAccessPoint);
}
@@ -331,8 +353,8 @@
mContext = context;
}
- public Drawable getIcon(int level) {
- return mContext.getDrawable(Utils.getWifiIconResource(level));
+ public Drawable getIcon(int level, int generation, boolean isReady) {
+ return mContext.getDrawable(Utils.getWifiIconResource(level, generation, isReady));
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index b11585a..e19013e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -75,6 +75,9 @@
public int rssi;
public int level;
public String statusLabel;
+ public int wifiGeneration;
+ public boolean vhtMax8SpatialStreamsSupport;
+ public boolean twtSupport;
public WifiStatusTracker(Context context, WifiManager wifiManager,
NetworkScoreManager networkScoreManager, ConnectivityManager connectivityManager,
@@ -126,6 +129,9 @@
}
updateRssi(mWifiInfo.getRssi());
maybeRequestNetworkScore();
+ wifiGeneration = mWifiInfo.getWifiGeneration();
+ vhtMax8SpatialStreamsSupport = mWifiInfo.isVhtMax8SpatialStreamsSupported();
+ twtSupport = mWifiInfo.isTwtSupported();
}
}
updateStatusLabel();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index d3bab5f..2933b2f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -854,6 +854,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ sVerboseLogging = (mWifiManager.getVerboseLoggingLevel() > 0);
if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
updateWifiState(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 658a0b5..423a4ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -86,6 +86,7 @@
StringBuilder visibility = new StringBuilder();
StringBuilder scans24GHz = new StringBuilder();
StringBuilder scans5GHz = new StringBuilder();
+ StringBuilder scans60GHz = new StringBuilder();
String bssid = null;
if (accessPoint.isActive() && info != null) {
@@ -108,9 +109,11 @@
int maxRssi5 = WifiConfiguration.INVALID_RSSI;
int maxRssi24 = WifiConfiguration.INVALID_RSSI;
+ int maxRssi60 = WifiConfiguration.INVALID_RSSI;
final int maxDisplayedScans = 4;
int num5 = 0; // number of scanned BSSID on 5GHz band
int num24 = 0; // number of scanned BSSID on 2.4Ghz band
+ int num60 = 0; // number of scanned BSSID on 60Ghz band
int numBlackListed = 0;
// TODO: sort list by RSSI or age
@@ -145,6 +148,19 @@
verboseScanResultSummary(accessPoint, result, bssid,
nowMs));
}
+ } else if (result.frequency >= AccessPoint.LOWER_FREQ_60GHZ
+ && result.frequency <= AccessPoint.HIGHER_FREQ_60GHZ) {
+ // Strictly speaking: [60000, 61000]
+ num60++;
+
+ if (result.level > maxRssi60) {
+ maxRssi60 = result.level;
+ }
+ if (num60 <= maxDisplayedScans) {
+ scans60GHz.append(
+ verboseScanResultSummary(accessPoint, result, bssid,
+ nowMs));
+ }
}
}
visibility.append(" [");
@@ -163,6 +179,14 @@
}
visibility.append(scans5GHz.toString());
}
+ visibility.append(";");
+ if (num60 > 0) {
+ visibility.append("(").append(num60).append(")");
+ if (num60 > maxDisplayedScans) {
+ visibility.append("max=").append(maxRssi60).append(",");
+ }
+ visibility.append(scans60GHz.toString());
+ }
if (numBlackListed > 0) {
visibility.append("!").append(numBlackListed);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index c555cbe..2e69619 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -129,7 +129,7 @@
private static String KNOWN_CODEC_LABEL = "Use high quality audio: %1$s";
private static String UNKNOWN_CODEC_LABEL = "Use high quality audio";
private static String[] CODEC_NAMES =
- new String[]{"Default", "SBC", "AAC", "aptX", "aptX HD", "LDAC"};
+ new String[] { "Default", "SBC", "AAC", "aptX", "aptX HD", "LDAC", "aptX Adaptive", "aptX TWS+" };
/**
* Helper for setting up several tests of getHighQualityAudioOptionLabel
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index 3a571f9..1896d7e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -65,6 +65,7 @@
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mContext).getApplicationContext();
+ doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 05246a4..cdc199b 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -218,6 +218,9 @@
<!-- Default for Settings.Global.APPLY_RAMPING_RINGER -->
<bool name="def_apply_ramping_ringer">false</bool>
+ <!-- Default for Settings.Global.NTP_SERVER_2's property name -->
+ <string name="def_ntp_server_2" translatable="false">persist.vendor.ntp.svr_2</string>
+
<!-- Default for Settings.Secure.CHARGING_VIBRATION_ENABLED -->
<bool name="def_charging_vibration_enabled">true</bool>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 146f30d..e9c1dc9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -69,6 +69,7 @@
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global
Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global
Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global
+ Settings.Secure.WIFI_DISCONNECT_DELAY_DURATION,
Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND,
Settings.Secure.MOUNT_UMS_AUTOSTART,
Settings.Secure.MOUNT_UMS_PROMPT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index f7fc0c5..ad63611 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -107,6 +107,7 @@
VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.WIFI_DISCONNECT_DELAY_DURATION, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.MOUNT_PLAY_NOTIFICATION_SND, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MOUNT_UMS_AUTOSTART, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.MOUNT_UMS_PROMPT, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 44de09b..56deb1c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2569,8 +2569,8 @@
for (int phoneId = 0;
phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) {
mode = TelephonyManager.getTelephonyProperty(phoneId,
- "ro.telephony.default_network",
- Integer.toString(RILConstants.PREFERRED_NETWORK_MODE));
+ "ro.telephony.default_network",
+ Integer.toString(RILConstants.NETWORK_MODE_WCDMA_PREF));
if (phoneId == 0) {
val = mode;
} else {
@@ -2609,6 +2609,8 @@
defaultLidBehavior = 0;
}
loadSetting(stmt, Settings.Global.LID_BEHAVIOR, defaultLidBehavior);
+ loadStringSetting(stmt, Settings.Global.NTP_SERVER_2,
+ R.string.def_ntp_server_2);
/*
* IMPORTANT: Do not add any more upgrade steps here as the global,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e24d387..84e63be 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1135,6 +1135,9 @@
dumpSetting(s, p,
Settings.Global.NTP_TIMEOUT,
GlobalSettingsProto.Ntp.TIMEOUT_MS);
+ dumpSetting(s, p,
+ Settings.Global.NTP_SERVER_2,
+ GlobalSettingsProto.Ntp.SERVER_2);
p.end(ntpToken);
final long uasbToken = p.start(GlobalSettingsProto.USER_ABSENT_SMALL_BATTERY);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 80faf476..40b7111 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -4093,6 +4093,16 @@
null, true, SettingsState.SYSTEM_PACKAGE_NAME);
}
+ // Update the settings for NTP_SERVER_2
+ final Setting currentSetting = globalSettings.getSettingLocked(
+ Global.NTP_SERVER_2);
+ if (currentSetting.isNull()) {
+ globalSettings.insertSettingLocked(
+ Global.NTP_SERVER_2,
+ getContext().getResources().getString(
+ R.string.def_ntp_server_2),
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+ }
currentVersion = 170;
}
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index d2f168e..9a75ac4 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -563,6 +563,10 @@
protected void onStop() {
super.onStop();
+ // must remove mHandler 's callback, or will result in one random issue:
+ // media playback occurs even though this activity has been destroyed.
+ mHandler.removeCallbacks(this);
+
if (!isChangingConfigurations()) {
stopAnyPlayingRingtone();
} else {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 0c582c4..c647e54 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -68,7 +68,11 @@
manifest: "AndroidManifest.xml",
libs: [
+ "android.car",
+ "android.car.userlib",
"telephony-common",
+ "telephony-ext",
+ "ims-common",
],
kotlincflags: ["-Xjvm-default=enable"],
@@ -135,6 +139,8 @@
"android.test.runner",
"telephony-common",
"android.test.base",
+ "telephony-ext",
+ "ims-common",
],
kotlincflags: ["-Xjvm-default=enable"],
aaptflags: [
@@ -161,7 +167,11 @@
},
libs: [
+ "android.car",
+ "android.car.userlib",
+ "ims-common",
"telephony-common",
+ "telephony-ext",
],
kotlincflags: ["-Xjvm-default=enable"],
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index e4438f9..3f6b89e 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -107,6 +107,10 @@
<item quantity="other">SIM 卡 PIN 码不正确,您还有 <xliff:g id="NUMBER_1">%d</xliff:g> 次尝试机会。</item>
<item quantity="one">SIM 卡 PIN 码不正确,您还有 <xliff:g id="NUMBER_0">%d</xliff:g> 次尝试机会。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
</plurals>
+ <plurals name="kg_password_wrong_pin_code_multi_sim" formatted="false">
+ <item quantity="other">SIM 卡<xliff:g id="slotid">%d</xliff:g> PIN 码不正确,您还有 <xliff:g id="NUMBER_1">%d</xliff:g> 次尝试机会。</item>
+ <item quantity="one">SIM 卡<xliff:g id="slotid">%d</xliff:g> PIN 码不正确,您还有 <xliff:g id="NUMBER_0">%d</xliff:g> 次尝试机会。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
+ </plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"SIM 卡无法使用,请与您的运营商联系。"</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
<item quantity="other">SIM 卡 PUK 码不正确,您还有 <xliff:g id="NUMBER_1">%d</xliff:g> 次尝试机会。如果仍不正确,SIM 卡将永远无法使用。</item>
@@ -147,6 +151,10 @@
<item quantity="other">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">请输入 SIM 卡 PIN 码,您还可以尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
</plurals>
+ <plurals name="kg_password_default_pin_message_multi_sim" formatted="false">
+ <item quantity="other">请输入 SIM 卡<xliff:g id="slotid">%d</xliff:g> PIN 码,您还可以尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">请输入 SIM 卡<xliff:g id="slotid">%d</xliff:g> PIN 码,您还可以尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
+ </plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
<item quantity="other">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
<item quantity="one">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 4134527..9e49732 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -107,6 +107,10 @@
<item quantity="other">SIM 卡的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。</item>
<item quantity="one">SIM 卡的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_0">%d</xliff:g> 次輸入機會。如果仍然輸入錯誤,您必須聯絡流動網絡供應商為您的裝置解鎖。</item>
</plurals>
+ <plurals name="kg_password_wrong_pin_code_multi_sim" formatted="false">
+ <item quantity="other">SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。</item>
+ <item quantity="one">SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_0">%d</xliff:g> 次輸入機會。如果仍然輸入錯誤,您必須聯絡流動網絡供應商為您的裝置解鎖。</item>
+ </plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"SIM 卡無法使用,請聯絡您的流動網絡供應商。"</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
<item quantity="other">SIM 卡的 PUK 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。如果仍然輸入錯誤,SIM 卡將永久無法使用。</item>
@@ -147,6 +151,10 @@
<item quantity="other">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">輸入 SIM 卡的 PIN,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,您必須聯絡流動網絡供應商解鎖您的裝置。</item>
</plurals>
+ <plurals name="kg_password_default_pin_message_multi_sim" formatted="false">
+ <item quantity="other">輸入 SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">輸入 SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,您必須聯絡流動網絡供應商解鎖您的裝置。</item>
+ </plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
<item quantity="other">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
<item quantity="one">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index fd95559..6f0d2e7 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -107,6 +107,10 @@
<item quantity="other">SIM 卡的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">SIM 卡的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
</plurals>
+ <plurals name="kg_password_wrong_pin_code_multi_sim" formatted="false">
+ <item quantity="other">SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
+ </plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"SIM 卡無法使用,請與你的電信業者聯絡。"</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
<item quantity="other">SIM 卡的 PUK 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。如果仍然失敗,SIM 卡將永久無法使用。</item>
@@ -147,6 +151,10 @@
<item quantity="other">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
<item quantity="one">請輸入 SIM 卡的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
</plurals>
+ <plurals name="kg_password_default_pin_message_multi_sim" formatted="false">
+ <item quantity="other">請輸入 SIM 卡<xliff:g id="slotid">%d</xliff:g>的 PIN 碼,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+ <item quantity="one">請輸入 SIM 卡的<xliff:g id="slotid">%d</xliff:g> PIN 碼,你還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請電信業者為裝置解鎖。</item>
+ </plurals>
<plurals name="kg_password_default_puk_message" formatted="false" msgid="8744416410184198352">
<item quantity="other">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
<item quantity="one">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 485240a..7528d58 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -303,6 +303,10 @@
<item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
<item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
</plurals>
+ <plurals name="kg_password_wrong_pin_code_multi_sim">
+ <item quantity="one">Incorrect SIM<xliff:g id="slotid">%d</xliff:g> PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Incorrect SIM<xliff:g id="slotid">%d</xliff:g> PIN code, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
+ </plurals>
<!-- Instructions telling the user that they have exhausted SIM PUK retries and the SIM is now unusable.
Displayed in a dialog box. -->
@@ -398,6 +402,10 @@
<item quantity="other">Enter SIM PIN. You have <xliff:g id="number">%d</xliff:g> remaining
attempts.</item>
</plurals>
+ <plurals name="kg_password_default_pin_message_multi_sim">
+ <item quantity="one">Enter SIM<xliff:g id="slotid">%d</xliff:g> PIN, you have <xliff:g id="number">%d</xliff:g> remaining attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Enter SIM<xliff:g id="slotid">%d</xliff:g> PIN, you have <xliff:g id="number">%d</xliff:g> remaining attempts.</item>
+ </plurals>
<!-- Instructions telling the user remaining times when enter SIM PUK view. -->
<plurals name="kg_password_default_puk_message">
diff --git a/packages/SystemUI/res/drawable/ic_5g_uwb_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_uwb_mobiledata.xml
new file mode 100644
index 0000000..41a82af
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_5g_uwb_mobiledata.xml
@@ -0,0 +1,49 @@
+<!--Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="14dp"
+ android:viewportWidth="36"
+ android:viewportHeight="14">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M2.4,5.5c-0.3,0-0.6,0.1-0.9,0.2C2.3,5.8,2.2,5.9,2,6.1l0.3-2.8h3.4v-1H1.1L0.6,7.4l1.1,0.1C1.9,7.2,2.1,7,2.2,6.9c0.2-0.2,0.5-0.3,0.9-0.3s0.9,0.2,1,0.6C4.5,7.5,4.6,8,4.6,8.7s-0.1,1.2-0.4,1.6c-0.3,0.4-0.6,0.6-1,0.6c-0.4,0-0.8-0.2-0.9-0.5C2,10.1,1.9,9.7,1.9,9.1H0.6l0,0c0,0.9,0.2,1.5,0.8,1.9c0.5,0.5,1.1,0.7,1.9,0.7c0.9,0,1.6-0.3,2.1-0.9S6,9.5,6,8.6c0-0.9-0.2-1.7-0.7-2.3C4.8,5.8,4.2,5.5,3.4,5.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M9.5,7v0.9h1.7v2.2c-0.1,0.2-0.3,0.4-0.6,0.5s-0.7,0.2-1,0.2c-0.6,0-1-0.2-1.4-0.7C7.8,9.7,7.6,9.1,7.6,8.3V5.4c0-0.8,0.2-1.4,0.5-1.8C8.5,3.3,9,3.1,9.5,3.1c0.6,0,0.9,0.2,1.2,0.5c0.3,0.3,0.5,0.8,0.5,1.3h1.2l0,0c0-0.9-0.2-1.5-0.8-2c-0.5-0.5-1.2-0.8-2.2-0.8c-0.9,0-1.7,0.3-2.4,0.9S6.3,4.4,6.3,5.5v2.8c0,1.1,0.3,2,0.9,2.6c0.6,0.6,1.4,0.9,2.4,0.9c0.8,0,1.4-0.1,1.9-0.4c0.5-0.3,0.9-0.6,1-0.9V7H9.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M17.5,2.2v6.3c0,1.7,0.6,2.2,1.3,2.2c0.8,0,1.3-0.6,1.3-2.2V2.2h1.1v6.1c0,2.4-1,3.3-2.4,3.3c-1.4,0-2.3-0.9-2.3-3.2V2.2H17.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M23.5,11.5l-1.8-9.3h1.1l0.8,4.5c0.2,1.2,0.3,2.2,0.5,3.4h0.1c0.1-1.2,0.3-2.2,0.6-3.4l0.9-4.5h0.9l0.9,4.4c0.2,1.1,0.4,2.2,0.5,3.5h0c0.2-1.3,0.3-2.4,0.5-3.4l0.8-4.4h1l-1.8,9.3h-1L26.4,7c-0.2-1-0.4-2-0.5-3.1h0C25.8,5,25.7,6,25.4,7l-0.9,4.5H23.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M30.8,2.2c0.5,0,1,0,1.6,0c0.8,0,1.6,0.2,2.1,0.7c0.4,0.4,0.6,0.9,0.6,1.6c0,1-0.5,1.7-1.4,2.1v0c1.1,0.3,1.7,1.2,1.7,2.4c0,0.8-0.2,1.4-0.7,1.9c-0.5,0.6-1.4,0.8-2.5,0.8c-0.7,0-1.1,0-1.4-0.1V2.2zM31.9,6.1h0.5c0.9,0,1.6-0.7,1.6-1.6C34,3.6,33.6,3,32.5,3C32.2,3,32,3,31.9,3V6.1zM31.9,10.7c0.1,0,0.3,0.1,0.5,0.1c1.1,0,1.8-0.7,1.8-1.9c0-1.3-0.9-1.9-1.9-1.9h-0.5V10.7z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
index 694b0dd..7c7b7d7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
@@ -23,6 +23,5 @@
android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2.01C7.25,2.01 2.97,4.09 0,7.4L7.582,16.625C7.582,16.627 7.58,16.629 7.58,16.631L11.99,22L12,22L13,20.789L13,17.641L13,13.119C12.68,13.039 12.34,13 12,13C10.601,13 9.351,13.64 8.531,14.639L2.699,7.539C5.269,5.279 8.58,4.01 12,4.01C15.42,4.01 18.731,5.279 21.301,7.539L16.811,13L19.4,13L24,7.4C21.03,4.09 16.75,2.01 12,2.01z"
- android:fillAlpha="0.3"/>
+ android:pathData="M12,2.01C7.25,2.01 2.97,4.09 0,7.4L7.582,16.625C7.582,16.627 7.58,16.629 7.58,16.631L11.99,22L12,22L13,20.789L13,17.641L13,13.119C12.68,13.039 12.34,13 12,13C10.601,13 9.351,13.64 8.531,14.639L2.699,7.539C5.269,5.279 8.58,4.01 12,4.01C15.42,4.01 18.731,5.279 21.301,7.539L16.811,13L19.4,13L24,7.4C21.03,4.09 16.75,2.01 12,2.01z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
index dcb3fa8..be95f84 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
@@ -23,6 +23,5 @@
android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L12,22L13,20.779L13,17.631L13,13L16.801,13L18,13L19.391,13L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C14.747,4 17.423,4.819 19.701,6.313C20.259,6.678 20.795,7.085 21.301,7.529L17.389,12.287C16.029,10.868 14.119,9.99 12,9.99C9.88,9.99 7.969,10.869 6.609,12.289L2.699,7.529C5.269,5.269 8.58,4 12,4z"
- android:fillAlpha="0.3"/>
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L12,22L13,20.779L13,17.631L13,13L16.801,13L18,13L19.391,13L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C14.747,4 17.423,4.819 19.701,6.313C20.259,6.678 20.795,7.085 21.301,7.529L17.389,12.287C16.029,10.868 14.119,9.99 12,9.99C9.88,9.99 7.969,10.869 6.609,12.289L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
index d68a2f6..29cb864 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
@@ -23,6 +23,5 @@
android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L3.301,11.41L12,22L13,20.779L13,17.631L13,13L16.801,13L19.391,13L20.699,11.41C20.699,11.409 20.698,11.409 20.697,11.408L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C15.42,4 18.731,5.269 21.301,7.529L19.35,9.9C17.43,8.1 14.86,6.99 12,6.99C9.14,6.99 6.57,8.1 4.65,9.9C4.65,9.901 4.649,9.902 4.648,9.902L2.699,7.529C5.269,5.269 8.58,4 12,4z"
- android:fillAlpha="0.3"/>
+ android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L3.301,11.41L12,22L13,20.779L13,17.631L13,13L16.801,13L19.391,13L20.699,11.41C20.699,11.409 20.698,11.409 20.697,11.408L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C15.42,4 18.731,5.269 21.301,7.529L19.35,9.9C17.43,8.1 14.86,6.99 12,6.99C9.14,6.99 6.57,8.1 4.65,9.9C4.65,9.901 4.649,9.902 4.648,9.902L2.699,7.529C5.269,5.269 8.58,4 12,4z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
index 886cc35..3b298c5 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
@@ -20,8 +20,7 @@
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.08 0,7.39L12,22l1,-1.22V13h6.39L24,7.39C21.03,4.08 16.75,2 12,2z"
- android:fillAlpha="0.3"/>
+ android:pathData="M12,2C7.25,2 2.97,4.08 0,7.39L12,22l1,-1.22V13h6.39L24,7.39C21.03,4.08 16.75,2 12,2z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4_0.xml
new file mode 100644
index 0000000..31159a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4_0.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="29.5dp"
+ android:viewportWidth="30"
+ android:viewportHeight="24">
+ <group
+ android:translateX="0.8"
+ android:translateY="-0.9">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 2.3281583,14.028369 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.822012,1.822009 -1.830163,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.001793,0.38 1.381793,0 l 1.830155,-1.830164 1.830163,1.830163 c 0.38,0.39 1.001796,0.379999 1.381793,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 l -1.830163,-1.830164 1.830163,-1.830163 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.997718,-0.38 -1.377717,0 l -1.821926,1.822011 -1.82201,-1.822011 c -0.19,-0.19 -0.438859,-0.285326 -0.688859,-0.285326 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- number 4-->
+ <path
+ android:pathData="m 26.892869,17.71889 h -1.056598 v 1.849791 H 24.330062 V 17.71889 h -3.602534 v -1.359946 l 3.344006,-5.871601 h 1.764737 v 5.884492 h 1.056598 z m -2.562807,-1.347055 v -2.971248 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- light signal level 4-->
+ <path
+ android:pathData="M 12,3 C 6.44,3 2.3284239,5.360652 0.55842392,6.570652 c -0.51,0.35 -0.6082608,1.060761 -0.2282609,1.540761 L 3.4524458,12 h 6.6644022 v 8.298912 l 1.043478,1.300271 c 0.42,0.530001 1.228968,0.530001 1.658968,0 l 6.505435,-8.091032 a 4.0677967,4.4745761 0 0 1 -0.0041,-0.0856 4.0677967,4.4745761 0 0 1 3.64402,-4.44701 l 0.697013,-0.86413 c 0.39,-0.48 0.28989,-1.190761 -0.22011,-1.540761 C 21.671576,5.360652 17.55,3 12,3 Z"
+ android:fillColor="#4DFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4_1.xml
new file mode 100644
index 0000000..2c23182
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4_1.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 4-->
+ <path
+ android:pathData="m 25.107866,17.646981 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.871601 h 1.764737 v 5.884492 h 1.056598 z m -2.562807,-1.347055 v -2.971248 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 1-->
+ <path
+ android:pathData="M 11.999999,2.002712 C 7.25,2.002712 2.969999,4.081299 -9.9999999e-7,7.391299 L 4.133152,12.425266 H 6.721467 L 2.698369,7.529886 c 2.569999,-2.26 5.881631,-3.529891 9.30163,-3.529891 3.42,0 6.731632,1.269891 9.30163,3.529891 l -5.836956,7.104619 c -0.820053,-0.997437 -2.066757,-1.634511 -3.464674,-1.634511 -0.175,0 -0.339745,0.03762 -0.509511,0.05707 v 5.17663 3.14674 l 0.509511,0.619563 4.418479,-5.368205 c -6.04e-4,-0.003 -0.0035,-0.0052 -0.0041,-0.0082 l 2.771739,-3.370924 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.010869,-1.230978 c -2.970002,-3.31005 -7.25,-5.388637 -12,-5.388637 z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4_2.xml
new file mode 100644
index 0000000..b1bec7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4_2.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 4-->
+ <path
+ android:pathData="m 25.107866,17.646981 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.871601 h 1.764737 v 5.884492 h 1.056598 z m -2.562807,-1.347055 v -2.971248 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 2-->
+ <path
+ android:pathData="m 11.999999,2.002716 c -4.7500004,0 -9.03,2.078587 -12.00000007,5.388587 L 4.133151,12.42527 H 6.7214663 L 6.6114119,12.290759 h 4.8790761 v 5.942935 3.14674 L 11.94701,21.93478 12,22 19.186141,13.252719 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z m 0,1.997282 c 3.42,0 6.731631,1.269891 9.30163,3.529892 l -3.908967,4.760869 c -0.01997,-0.02087 -0.03686,-0.04459 -0.05706,-0.06522 -1.359999,-1.42 -3.268587,-2.298914 -5.388587,-2.298914 -2.120001,0 -4.0285872,0.878914 -5.3885872,2.298914 L 2.6983684,7.52989 C 5.2683675,5.269889 8.5799987,3.999998 11.999999,3.999998 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4_3.xml
new file mode 100644
index 0000000..5925bd1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4_3.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 4-->
+ <path
+ android:pathData="m 25.107866,17.646981 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.871601 h 1.764737 v 5.884492 h 1.056598 z m -2.562807,-1.347055 v -2.971248 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 3-->
+ <path
+ android:pathData="m 11.999999,1.868205 c -4.75,0 -9.030001,2.078587 -12.0000010434783,5.388587 L 3.301629,11.275813 4.13315,12.290759 h 2.588316 4.769022 v 5.808424 3.14674 l 0.509511,0.619563 7.129076,-8.677988 0.05706,-0.06929 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774456 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.970003,-3.31 -7.250001,-5.388587 -12,-5.388587 z m 0,1.997283 c 3.42,0 6.731631,1.269891 9.30163,3.529891 L 19.349183,9.771737 C 17.427804,7.959487 14.85815,6.857335 11.999999,6.857335 c -2.8581,0 -5.427817,1.111503 -7.349186,2.914402 L 2.698368,7.395379 c 2.569999,-2.26 5.881631,-3.529891 9.301631,-3.529891 z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4_4.xml
new file mode 100644
index 0000000..eed48dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4_4.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="26"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 4-->
+ <path
+ android:pathData="m 25.107866,17.646981 h -1.056598 v 1.849791 h -1.506209 v -1.849791 h -3.602534 v -1.359946 l 3.344006,-5.871601 h 1.764737 v 5.884492 h 1.056598 z m -2.562807,-1.347055 v -2.971248 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.203274 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 4-->
+ <path
+ android:pathData="M 12,2.001359 C 7.2500003,2.001359 2.9700004,4.0799457 3.45e-7,7.3899455 L 4.0230983,12.289402 h 7.4673907 v 9.089674 L 12,21.998641 19.263587,13.157609 A 3.4516399,3.5235489 0 0 1 19.129076,12.1875 3.4516399,3.5235489 0 0 1 22.577445,8.6657608 3.4516399,3.5235489 0 0 1 22.936141,8.6820598 L 24,7.3899455 C 21.03,4.0799457 16.75,2.001359 12,2.001359 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_5_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_5_0.xml
new file mode 100644
index 0000000..e286ade
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_5_0.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="29.5dp"
+ android:viewportWidth="30"
+ android:viewportHeight="24">
+ <group
+ android:translateX="0.8"
+ android:translateY="-0.9">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 2.3281583,14.028369 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.822012,1.822009 -1.830163,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.001793,0.38 1.381793,0 l 1.830155,-1.830164 1.830163,1.830163 c 0.38,0.39 1.001796,0.379999 1.381793,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 l -1.830163,-1.830164 1.830163,-1.830163 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.997718,-0.38 -1.377717,0 l -1.821926,1.822011 -1.82201,-1.822011 c -0.19,-0.19 -0.438859,-0.285326 -0.688859,-0.285326 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- number 5-->
+ <path
+ android:pathData="m 27.651626,16.765723 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- light signal level 4-->
+ <path
+ android:pathData="M 12,3 C 6.44,3 2.3284239,5.360652 0.55842392,6.570652 c -0.51,0.35 -0.6082608,1.060761 -0.2282609,1.540761 L 3.4524458,12 h 6.6644022 v 8.298912 l 1.043478,1.300271 c 0.42,0.530001 1.228968,0.530001 1.658968,0 l 6.505435,-8.091032 a 4.0677967,4.4745761 0 0 1 -0.0041,-0.0856 4.0677967,4.4745761 0 0 1 3.64402,-4.44701 l 0.697013,-0.86413 c 0.39,-0.48 0.28989,-1.190761 -0.22011,-1.540761 C 21.671576,5.360652 17.55,3 12,3 Z"
+ android:fillColor="#4DFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_5_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_5_1.xml
new file mode 100644
index 0000000..c29ef43
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_5_1.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 5-->
+ <path
+ android:pathData="m 26.712686,15.940325 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 1-->
+ <path
+ android:pathData="M 11.999999,2.002712 C 7.25,2.002712 2.969999,4.081299 -9.9999999e-7,7.391299 L 4.133152,12.425266 H 6.721467 L 2.698369,7.529886 c 2.569999,-2.26 5.881631,-3.529891 9.30163,-3.529891 3.42,0 6.731632,1.269891 9.30163,3.529891 l -5.836956,7.104619 c -0.820053,-0.997437 -2.066757,-1.634511 -3.464674,-1.634511 -0.175,0 -0.339745,0.03762 -0.509511,0.05707 v 5.17663 3.14674 l 0.509511,0.619563 4.418479,-5.368205 c -6.04e-4,-0.003 -0.0035,-0.0052 -0.0041,-0.0082 l 2.771739,-3.370924 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.010869,-1.230978 c -2.970002,-3.31005 -7.25,-5.388637 -12,-5.388637 z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_5_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_5_2.xml
new file mode 100644
index 0000000..69fa600
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_5_2.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 5-->
+ <path
+ android:pathData="m 26.712686,15.940325 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 2-->
+ <path
+ android:pathData="m 11.999999,2.002716 c -4.7500004,0 -9.03,2.078587 -12.00000007,5.388587 L 4.133151,12.42527 H 6.7214663 L 6.6114119,12.290759 h 4.8790761 v 5.942935 3.14674 L 11.94701,21.93478 12,22 19.186141,13.252719 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z m 0,1.997282 c 3.42,0 6.731631,1.269891 9.30163,3.529892 l -3.908967,4.760869 c -0.01997,-0.02087 -0.03686,-0.04459 -0.05706,-0.06522 -1.359999,-1.42 -3.268587,-2.298914 -5.388587,-2.298914 -2.120001,0 -4.0285872,0.878914 -5.3885872,2.298914 L 2.6983684,7.52989 C 5.2683675,5.269889 8.5799987,3.999998 11.999999,3.999998 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_5_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_5_3.xml
new file mode 100644
index 0000000..f92fb8f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_5_3.xml
@@ -0,0 +1,47 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 5-->
+ <path
+ android:pathData="m 26.712686,15.940325 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 3-->
+ <path
+ android:pathData="m 11.999999,1.868205 c -4.75,0 -9.030001,2.078587 -12.0000010434783,5.388587 L 3.301629,11.275813 4.13315,12.290759 h 2.588316 4.769022 v 5.808424 3.14674 l 0.509511,0.619563 7.129076,-8.677988 0.05706,-0.06929 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774456 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.970003,-3.31 -7.250001,-5.388587 -12,-5.388587 z m 0,1.997283 c 3.42,0 6.731631,1.269891 9.30163,3.529891 L 19.349183,9.771737 C 17.427804,7.959487 14.85815,6.857335 11.999999,6.857335 c -2.8581,0 -5.427817,1.111503 -7.349186,2.914402 L 2.698368,7.395379 c 2.569999,-2.26 5.881631,-3.529891 9.301631,-3.529891 z"
+ android:fillColor="@android:color/white"/>
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_5_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_5_4.xml
new file mode 100644
index 0000000..abb2870
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_5_4.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 5-->
+ <path
+ android:pathData="m 26.712686,15.940325 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 4-->
+ <path
+ android:pathData="M 12,2.001359 C 7.2500003,2.001359 2.9700004,4.0799457 3.45e-7,7.3899455 L 4.0230983,12.289402 h 7.4673907 v 9.089674 L 12,21.998641 19.263587,13.157609 A 3.4516399,3.5235489 0 0 1 19.129076,12.1875 3.4516399,3.5235489 0 0 1 22.577445,8.6657608 3.4516399,3.5235489 0 0 1 22.936141,8.6820598 L 24,7.3899455 C 21.03,4.0799457 16.75,2.001359 12,2.001359 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_6_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_6_0.xml
new file mode 100644
index 0000000..280589c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_6_0.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="29.5dp"
+ android:viewportWidth="30"
+ android:viewportHeight="24">
+ <group
+ android:translateX="0.8"
+ android:translateY="-0.9">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 2.3281583,14.028369 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.822012,1.822009 -1.830163,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.001793,0.38 1.381793,0 l 1.830155,-1.830164 1.830163,1.830163 c 0.38,0.39 1.001796,0.379999 1.381793,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 l -1.830163,-1.830164 1.830163,-1.830163 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.997718,-0.38 -1.377717,0 l -1.821926,1.822011 -1.82201,-1.822011 c -0.19,-0.19 -0.438859,-0.285326 -0.688859,-0.285326 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- number 6-->
+ <path
+ android:pathData="m 27.397427,16.704042 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="#FFFFFFFF"/>
+ <!-- light signal level 4-->
+ <path
+ android:pathData="M 12,3 C 6.44,3 2.3284239,5.360652 0.55842392,6.570652 c -0.51,0.35 -0.6082608,1.060761 -0.2282609,1.540761 L 3.4524458,12 h 6.6644022 v 8.298912 l 1.043478,1.300271 c 0.42,0.530001 1.228968,0.530001 1.658968,0 l 6.505435,-8.091032 a 4.0677967,4.4745761 0 0 1 -0.0041,-0.0856 4.0677967,4.4745761 0 0 1 3.64402,-4.44701 l 0.697013,-0.86413 c 0.39,-0.48 0.28989,-1.190761 -0.22011,-1.540761 C 21.671576,5.360652 17.55,3 12,3 Z"
+ android:fillColor="#4DFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_6_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_6_1.xml
new file mode 100644
index 0000000..74d5bb6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_6_1.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 6-->
+ <path
+ android:pathData="m 26.554082,16.242125 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 1-->
+ <path
+ android:pathData="M 11.999999,2.002712 C 7.25,2.002712 2.969999,4.081299 -9.9999999e-7,7.391299 L 4.133152,12.425266 H 6.721467 L 2.698369,7.529886 c 2.569999,-2.26 5.881631,-3.529891 9.30163,-3.529891 3.42,0 6.731632,1.269891 9.30163,3.529891 l -5.836956,7.104619 c -0.820053,-0.997437 -2.066757,-1.634511 -3.464674,-1.634511 -0.175,0 -0.339745,0.03762 -0.509511,0.05707 v 5.17663 3.14674 l 0.509511,0.619563 4.418479,-5.368205 c -6.04e-4,-0.003 -0.0035,-0.0052 -0.0041,-0.0082 l 2.771739,-3.370924 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.010869,-1.230978 c -2.970002,-3.31005 -7.25,-5.388637 -12,-5.388637 z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_6_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_6_2.xml
new file mode 100644
index 0000000..b583f27
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_6_2.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 6-->
+ <path
+ android:pathData="m 26.554082,16.242125 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 2-->
+ <path
+ android:pathData="m 11.999999,2.002716 c -4.7500004,0 -9.03,2.078587 -12.00000007,5.388587 L 4.133151,12.42527 H 6.7214663 L 6.6114119,12.290759 h 4.8790761 v 5.942935 3.14674 L 11.94701,21.93478 12,22 19.186141,13.252719 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774457 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.97,-3.31 -7.25,-5.388587 -12,-5.388587 z m 0,1.997282 c 3.42,0 6.731631,1.269891 9.30163,3.529892 l -3.908967,4.760869 c -0.01997,-0.02087 -0.03686,-0.04459 -0.05706,-0.06522 -1.359999,-1.42 -3.268587,-2.298914 -5.388587,-2.298914 -2.120001,0 -4.0285872,0.878914 -5.3885872,2.298914 L 2.6983684,7.52989 C 5.2683675,5.269889 8.5799987,3.999998 11.999999,3.999998 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_6_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_6_3.xml
new file mode 100644
index 0000000..3a9db72
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_6_3.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 6-->
+ <path
+ android:pathData="m 26.554082,16.242125 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 3-->
+ <path
+ android:pathData="m 11.999999,1.868205 c -4.75,0 -9.030001,2.078587 -12.0000010434783,5.388587 L 3.301629,11.275813 4.13315,12.290759 h 2.588316 4.769022 v 5.808424 3.14674 l 0.509511,0.619563 7.129076,-8.677988 0.05706,-0.06929 a 3.762712,3.8644067 0 0 1 -0.08152,-0.774456 3.762712,3.8644067 0 0 1 3.762228,-3.86413 3.762712,3.8644067 0 0 1 0.122283,0.0082 l 1.01087,-1.230978 c -2.970003,-3.31 -7.250001,-5.388587 -12,-5.388587 z m 0,1.997283 c 3.42,0 6.731631,1.269891 9.30163,3.529891 L 19.349183,9.771737 C 17.427804,7.959487 14.85815,6.857335 11.999999,6.857335 c -2.8581,0 -5.427817,1.111503 -7.349186,2.914402 L 2.698368,7.395379 c 2.569999,-2.26 5.881631,-3.529891 9.301631,-3.529891 z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_6_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_6_4.xml
new file mode 100644
index 0000000..50a4a8e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_6_4.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="28"
+ android:viewportHeight="24">
+ <!-- no Internet -->
+ <path
+ android:pathData="m 3.3972509,13.819005 c -0.25,0 -0.498859,0.09533 -0.688859,0.285326 l -0.01223,0.01223 c -0.38,0.38 -0.38,0.997718 0,1.377718 l 1.8220122,1.822009 -1.8301632,1.830163 c -0.38,0.38 -0.38,0.997717 0,1.377717 l 0.0082,0.01223 c 0.38,0.38 1.0017933,0.38 1.3817933,0 l 1.8301549,-1.830164 1.8301631,1.830163 c 0.38,0.39 1.0017959,0.379999 1.3817929,0 0.3800012,-0.38 0.3800012,-1.001794 0,-1.381793 L 7.2899522,17.32444 9.1201151,15.494277 c 0.3800012,-0.38 0.3777722,-0.999946 -0.01231,-1.389946 -0.379999,-0.38 -0.9977179,-0.38 -1.3777169,0 L 5.9081621,15.926342 4.0861522,14.104331 c -0.19,-0.19 -0.438859,-0.285326 -0.6888593,-0.285326 z"
+ android:fillColor="@android:color/white"/>
+ <!-- number 6-->
+ <path
+ android:pathData="m 26.554082,16.242125 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="@android:color/white"/>
+ <!-- signal level 4-->
+ <path
+ android:pathData="M 12,2.001359 C 7.2500003,2.001359 2.9700004,4.0799457 3.45e-7,7.3899455 L 4.0230983,12.289402 h 7.4673907 v 9.089674 L 12,21.998641 19.263587,13.157609 A 3.4516399,3.5235489 0 0 1 19.129076,12.1875 3.4516399,3.5235489 0 0 1 22.577445,8.6657608 3.4516399,3.5235489 0 0 1 22.936141,8.6820598 L 24,7.3899455 C 21.03,4.0799457 16.75,2.001359 12,2.001359 Z"
+ android:fillColor="@android:color/white"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volte.xml b/packages/SystemUI/res/drawable/ic_volte.xml
new file mode 100644
index 0000000..e4c5d6d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volte.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="14dp"
+ android:height="17dp"
+ android:viewportWidth="14"
+ android:viewportHeight="17">
+
+ <path
+ android:pathData="M 1.2 4 H 13.7 V 13.2 H 1.2 V 4 Z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M1.9,12.6V4h0.8v3.5h3.2V4h0.8v8.6H5.9v-4H2.7v4H1.9z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M8,12.6V4h2.1c0.5,0,0.8,0,1.1,0.1c0.4,0.1,0.7,0.3,0.9,0.6c0.3,0.4,0.6,0.9,0.7,1.5s0.2,1.3,0.2,2c0,0.7-0.1,1.2-0.2,1.7c-0.1,0.5-0.2,0.9-0.4,1.3S12.2,11.8,12,12s-0.4,0.3-0.7,0.4s-0.6,0.1-1,0.1H8zM8.8,11.6h1.3c0.4,0,0.7-0.1,0.9-0.2c0.2-0.1,0.4-0.3,0.5-0.4c0.2-0.3,0.3-0.6,0.4-1.1c0.1-0.5,0.2-1,0.2-1.7c0-0.9-0.1-1.6-0.3-2.1c-0.2-0.5-0.5-0.8-0.8-1C11,5.1,10.6,5,10.1,5H8.8V11.6z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M 2 9 L 1 9 L 1 9 L 2 9 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volte_no_voice.xml b/packages/SystemUI/res/drawable/ic_volte_no_voice.xml
new file mode 100644
index 0000000..490b624
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volte_no_voice.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="14dp"
+ android:height="17dp"
+ android:viewportWidth="14"
+ android:viewportHeight="17">
+
+ <path
+ android:pathData="M 1.2 4 H 13.7 V 13.2 H 1.2 V 4 Z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M1.9,12.6V4h0.8v3.5h3.2V4h0.8v8.6H5.9v-4H2.7v4H1.9z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M8,12.6V4h2.1c0.5,0,0.8,0,1.1,0.1c0.4,0.1,0.7,0.3,0.9,0.6c0.3,0.4,0.6,0.9,0.7,1.5s0.2,1.3,0.2,2c0,0.7-0.1,1.2-0.2,1.7c-0.1,0.5-0.2,0.9-0.4,1.3S12.2,11.8,12,12s-0.4,0.3-0.7,0.4s-0.6,0.1-1,0.1H8zM8.8,11.6h1.3c0.4,0,0.7-0.1,0.9-0.2c0.2-0.1,0.4-0.3,0.5-0.4c0.2-0.3,0.3-0.6,0.4-1.1c0.1-0.5,0.2-1,0.2-1.7c0-0.9-0.1-1.6-0.3-2.1c-0.2-0.5-0.5-0.8-0.8-1C11,5.1,10.6,5,10.1,5H8.8V11.6z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M 2 9 L 1 9 L 1 9 L 2 9 Z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M 0.5 9 H 13.5 V 10 H 0.5 V 9 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_wifi_4_hotspot.xml b/packages/SystemUI/res/drawable/ic_wifi_4_hotspot.xml
new file mode 100644
index 0000000..2895467
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_wifi_4_hotspot.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="54dp"
+ android:height="48dp"
+ android:viewportWidth="27.0"
+ android:viewportHeight="24.0">
+ <group
+ android:translateY="-0.32">
+ <path
+ android:pathData="m 11.951087,3.004076 c -0.36936,0.00196 -0.743424,0.022092 -1.120924,0.065217 -4.6200001,0.52 -8.3498914,4.3292391 -8.7798913,8.95924 a 9.966,9.966 0 0 0 4.0190217,9.012227 c 0.48,0.350001 1.1592392,0.200223 1.4592392,-0.309782 0.2499999,-0.43 0.1432065,-0.99212 -0.2567935,-1.29212 -2.28,-1.689999 -3.6530436,-4.549728 -3.1630435,-7.699728 0.54,-3.4999999 3.462337,-6.2907066 6.9823374,-6.6807066 3.778225,-0.4311254 7.072769,1.8079636 8.335598,5.0625006 A 7.7288137,8.3389834 0 0 1 20.910326,8.4864129 C 19.25166,5.2212048 15.864479,2.9832791 11.951087,3.004076 Z M 11.820652,7.0067935 A 6,6 0 0 0 11.25,7.0516305 C 8.6299999,7.3716306 6.4692934,9.4592936 6.0692934,12.069294 c -0.32,2.139999 0.489837,4.112662 1.919837,5.392662 0.48,0.43 1.2411412,0.327663 1.5611413,-0.232337 0.24,-0.42 0.1398908,-0.939511 -0.2201088,-1.25951 A 3.99,3.99 0 0 1 8.1114131,12.028533 3.954,3.954 0 0 1 11.009511,9.1182064 4.0069999,4.0069999 0 0 1 15.998642,12.998641 c 0,1.18 -0.508805,2.233315 -1.328805,2.963315 -0.36,0.33 -0.468261,0.847663 -0.228261,1.267663 0.31,0.54 1.04,0.69125 1.5,0.28125 A 5.97,5.97 0 0 0 18,12.998641 6,6 0 0 0 11.820652,7.0067935 Z m 0.179347,3.9945655 c -1.1,0 -2.0013592,0.897282 -2.0013592,1.997282 0,1.1 0.9013592,2.001359 2.0013592,2.001359 1.1,0 2.001359,-0.901359 2.001359,-2.001359 0,-1.1 -0.901359,-1.997282 -2.001359,-1.997282 z m 6.342393,6.843749 c -0.462479,0.60136 -1.002053,1.142421 -1.614131,1.59375 -0.4,0.3 -0.506793,0.85212 -0.256793,1.29212 0.3,0.519999 0.979239,0.659783 1.459239,0.309782 a 9.96,9.96 0 0 0 1.353261,-1.210597 7.7288137,8.3389834 0 0 1 -0.941576,-1.985055 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="m 25.46914,17.155238 h -1.056598 v 2.015506 H 22.906333 V 17.155238 H 19.303799 V 15.67346 l 3.344006,-6.3976129 h 1.764737 v 6.4116589 h 1.056598 z m -2.562807,-1.467732 v -3.23743 q 0,-0.379223 0.01967,-0.821649 0.01968,-0.442424 0.03092,-0.568836 v 0 q -0.146131,0.39327 -0.528296,1.137673 v 0 l -1.83781,3.490242 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_wifi_5_hotspot.xml b/packages/SystemUI/res/drawable/ic_wifi_5_hotspot.xml
new file mode 100644
index 0000000..b51ccc5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_wifi_5_hotspot.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="54dp"
+ android:height="48dp"
+ android:viewportWidth="27.0"
+ android:viewportHeight="24.0">
+ <group
+ android:translateY="-0.32">
+ <path
+ android:pathData="m 11.951087,3.004076 c -0.36936,0.00196 -0.743424,0.022092 -1.120924,0.065217 -4.6200001,0.52 -8.3498914,4.3292391 -8.7798913,8.95924 a 9.966,9.966 0 0 0 4.0190217,9.012227 c 0.48,0.350001 1.1592392,0.200223 1.4592392,-0.309782 0.2499999,-0.43 0.1432065,-0.99212 -0.2567935,-1.29212 -2.28,-1.689999 -3.6530436,-4.549728 -3.1630435,-7.699728 0.54,-3.4999999 3.462337,-6.2907066 6.9823374,-6.6807066 3.778225,-0.4311254 7.072769,1.8079636 8.335598,5.0625006 A 7.7288137,8.3389834 0 0 1 20.910326,8.4864129 C 19.25166,5.2212048 15.864479,2.9832791 11.951087,3.004076 Z M 11.820652,7.0067935 A 6,6 0 0 0 11.25,7.0516305 C 8.6299999,7.3716306 6.4692934,9.4592936 6.0692934,12.069294 c -0.32,2.139999 0.489837,4.112662 1.919837,5.392662 0.48,0.43 1.2411412,0.327663 1.5611413,-0.232337 0.24,-0.42 0.1398908,-0.939511 -0.2201088,-1.25951 A 3.99,3.99 0 0 1 8.1114131,12.028533 3.954,3.954 0 0 1 11.009511,9.1182064 4.0069999,4.0069999 0 0 1 15.998642,12.998641 c 0,1.18 -0.508805,2.233315 -1.328805,2.963315 -0.36,0.33 -0.468261,0.847663 -0.228261,1.267663 0.31,0.54 1.04,0.69125 1.5,0.28125 A 5.97,5.97 0 0 0 18,12.998641 6,6 0 0 0 11.820652,7.0067935 Z m 0.179347,3.9945655 c -1.1,0 -2.0013592,0.897282 -2.0013592,1.997282 0,1.1 0.9013592,2.001359 2.0013592,2.001359 1.1,0 2.001359,-0.901359 2.001359,-2.001359 0,-1.1 -0.901359,-1.997282 -2.001359,-1.997282 z m 6.342393,6.843749 c -0.462479,0.60136 -1.002053,1.142421 -1.614131,1.59375 -0.4,0.3 -0.506793,0.85212 -0.256793,1.29212 0.3,0.519999 0.979239,0.659783 1.459239,0.309782 a 9.96,9.96 0 0 0 1.353261,-1.210597 7.7288137,8.3389834 0 0 1 -0.941576,-1.985055 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="m 25.626571,16.562335 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.08008 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.55373 v 0 h -1.66729 l 0.29817,-4.825391 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.166251 q 0.62067,-0.54764 1.55167,-0.54764 v 0 q 1.22308,0 1.95632,0.76062 0.73324,0.76062 0.73324,2.06889 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_wifi_6_hotspot.xml b/packages/SystemUI/res/drawable/ic_wifi_6_hotspot.xml
new file mode 100644
index 0000000..9a77cfa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_wifi_6_hotspot.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="54dp"
+ android:height="48dp"
+ android:viewportWidth="27.0"
+ android:viewportHeight="24.0">
+ <group
+ android:translateY="-0.32">
+ <path
+ android:pathData="m 11.951087,3.004076 c -0.36936,0.00196 -0.743424,0.022092 -1.120924,0.065217 -4.6200001,0.52 -8.3498914,4.3292391 -8.7798913,8.95924 a 9.966,9.966 0 0 0 4.0190217,9.012227 c 0.48,0.350001 1.1592392,0.200223 1.4592392,-0.309782 0.2499999,-0.43 0.1432065,-0.99212 -0.2567935,-1.29212 -2.28,-1.689999 -3.6530436,-4.549728 -3.1630435,-7.699728 0.54,-3.4999999 3.462337,-6.2907066 6.9823374,-6.6807066 3.778225,-0.4311254 7.072769,1.8079636 8.335598,5.0625006 A 7.7288137,8.3389834 0 0 1 20.910326,8.4864129 C 19.25166,5.2212048 15.864479,2.9832791 11.951087,3.004076 Z M 11.820652,7.0067935 A 6,6 0 0 0 11.25,7.0516305 C 8.6299999,7.3716306 6.4692934,9.4592936 6.0692934,12.069294 c -0.32,2.139999 0.489837,4.112662 1.919837,5.392662 0.48,0.43 1.2411412,0.327663 1.5611413,-0.232337 0.24,-0.42 0.1398908,-0.939511 -0.2201088,-1.25951 A 3.99,3.99 0 0 1 8.1114131,12.028533 3.954,3.954 0 0 1 11.009511,9.1182064 4.0069999,4.0069999 0 0 1 15.998642,12.998641 c 0,1.18 -0.508805,2.233315 -1.328805,2.963315 -0.36,0.33 -0.468261,0.847663 -0.228261,1.267663 0.31,0.54 1.04,0.69125 1.5,0.28125 A 5.97,5.97 0 0 0 18,12.998641 6,6 0 0 0 11.820652,7.0067935 Z m 0.179347,3.9945655 c -1.1,0 -2.0013592,0.897282 -2.0013592,1.997282 0,1.1 0.9013592,2.001359 2.0013592,2.001359 1.1,0 2.001359,-0.901359 2.001359,-2.001359 0,-1.1 -0.901359,-1.997282 -2.001359,-1.997282 z m 6.342393,6.843749 c -0.462479,0.60136 -1.002053,1.142421 -1.614131,1.59375 -0.4,0.3 -0.506793,0.85212 -0.256793,1.29212 0.3,0.519999 0.979239,0.659783 1.459239,0.309782 a 9.96,9.96 0 0 0 1.353261,-1.210597 7.7288137,8.3389834 0 0 1 -0.941576,-1.985055 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="m 26.031315,16.070676 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.030264 v 0 q 0,-2.207557 0.875601,-3.323047 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 Q 23.827772,11.69655 22.974787,11.69655 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.702671 0.71082,1.908922 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0745 -0.358642,-0.37183 -0.985456,-0.37183 v 0 q -0.600966,0 -0.962838,0.348408 -0.361873,0.348407 -0.361873,0.922255 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_4_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_4_hotspot.xml
new file mode 100644
index 0000000..d9cfadd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_4_hotspot.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="22.0dp"
+ android:height="18.0dp"
+ android:viewportWidth="22.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:pathData="m 9.2771788,1.842391 c -0.5341993,-0.05549 -1.0854891,-0.0556 -1.6467391,0.0081 -3.4399999,0.39 -6.2098912,3.2184785 -6.5298912,6.6684783 -0.26000004,2.6099997 0.8777717,5.1510867 2.9877717,6.7010867 0.36,0.26 0.8623912,0.151739 1.0923913,-0.228261 0.1899999,-0.32 0.098424,-0.741957 -0.1915761,-0.961957 -1.7,-1.259997 -2.7078261,-3.380975 -2.3478261,-5.7309751 C 3.0413094,5.698863 5.2101681,3.620113 7.8301679,3.3301128 10.338407,3.0436568 12.553222,4.3446002 13.675277,6.3423412 A 7.0169487,8.1355924 0 0 1 14.478266,4.8097325 C 13.262879,3.1798315 11.402845,2.063138 9.2771788,1.842341 Z M 8.4986462,4.9605977 c -0.18,0 -0.3498912,0.00854 -0.5298912,0.028533 -1.86,0.23 -3.3884784,1.7125 -3.6684783,3.5624999 -0.2300001,1.5200004 0.351413,2.9092944 1.361413,3.8192934 0.34,0.3 0.8764674,0.228804 1.0964673,-0.171195 0.1699993,-0.3 0.1010337,-0.668587 -0.1589677,-0.888586 C 5.8191898,10.611142 5.4791354,9.5390216 5.7391354,8.5190215 c 0.25,-1.0199998 1.0425001,-1.8084238 2.0624999,-2.0584238 1.5200001,-0.38 3.0583697,0.5384239 3.4483697,2.0584238 0.06,0.2300002 0.08967,0.462935 0.08967,0.6929351 0,0.8400004 -0.361577,1.5791854 -0.941577,2.0991854 -0.25,0.23 -0.328968,0.600814 -0.158968,0.900814 0.22,0.38 0.739783,0.489729 1.059783,0.199729 0.92,-0.81 1.451087,-1.979728 1.451087,-3.1997284 0,-2.3500003 -1.901359,-4.2513589 -4.2513588,-4.2513589 z m 0,2.8288044 c -0.78,0 -1.4184783,0.6425543 -1.4184783,1.4225545 0,0.78 0.6384783,1.4184784 1.4184783,1.4184784 0.78,0 1.4225543,-0.6384784 1.4225543,-1.4184784 0,-0.7800002 -0.6425543,-1.4225545 -1.4225543,-1.4225545 z m 4.9361418,4.7160329 c -0.387159,0.579128 -0.84606,1.109077 -1.40625,1.524456 -0.3,0.22 -0.3775,0.631957 -0.1875,0.961957 0.22,0.39 0.728315,0.488261 1.088315,0.228261 0.438174,-0.322866 0.826135,-0.698796 1.177989,-1.100544 a 7.0169487,8.1355924 0 0 1 -0.672554,-1.61413 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M 20.617078,11.488485 H 19.56048 v 1.849791 H 18.054271 V 11.488485 H 14.451737 V 10.128539 L 17.795743,4.2569388 H 19.56048 V 10.14143 h 1.056598 z M 18.054271,10.14143 V 7.1701828 q 0,-0.348044 0.01967,-0.754093 0.01968,-0.406048 0.03092,-0.522067 v 0 q -0.146131,0.360936 -0.528296,1.044134 v 0 l -1.83781,3.2032732 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_5_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_5_hotspot.xml
new file mode 100644
index 0000000..aeb7aa4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_5_hotspot.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="22.0dp"
+ android:height="18.0dp"
+ android:viewportWidth="22.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:pathData="m 9.2771788,1.842391 c -0.5341993,-0.05549 -1.0854891,-0.0556 -1.6467391,0.0081 -3.4399999,0.39 -6.2098912,3.2184785 -6.5298912,6.6684783 -0.26000004,2.6099997 0.8777717,5.1510867 2.9877717,6.7010867 0.36,0.26 0.8623912,0.151739 1.0923913,-0.228261 0.1899999,-0.32 0.098424,-0.741957 -0.1915761,-0.961957 -1.7,-1.259997 -2.7078261,-3.380975 -2.3478261,-5.7309751 C 3.0413094,5.698863 5.2101681,3.620113 7.8301679,3.3301128 10.338407,3.0436568 12.553222,4.3446002 13.675277,6.3423412 A 7.0169487,8.1355924 0 0 1 14.478266,4.8097325 C 13.262879,3.1798315 11.402845,2.063138 9.2771788,1.842341 Z M 8.4986462,4.9605977 c -0.18,0 -0.3498912,0.00854 -0.5298912,0.028533 -1.86,0.23 -3.3884784,1.7125 -3.6684783,3.5624999 -0.2300001,1.5200004 0.351413,2.9092944 1.361413,3.8192934 0.34,0.3 0.8764674,0.228804 1.0964673,-0.171195 0.1699993,-0.3 0.1010337,-0.668587 -0.1589677,-0.888586 C 5.8191898,10.611142 5.4791354,9.5390216 5.7391354,8.5190215 c 0.25,-1.0199998 1.0425001,-1.8084238 2.0624999,-2.0584238 1.5200001,-0.38 3.0583697,0.5384239 3.4483697,2.0584238 0.06,0.2300002 0.08967,0.462935 0.08967,0.6929351 0,0.8400004 -0.361577,1.5791854 -0.941577,2.0991854 -0.25,0.23 -0.328968,0.600814 -0.158968,0.900814 0.22,0.38 0.739783,0.489729 1.059783,0.199729 0.92,-0.81 1.451087,-1.979728 1.451087,-3.1997284 0,-2.3500003 -1.901359,-4.2513589 -4.2513588,-4.2513589 z m 0,2.8288044 c -0.78,0 -1.4184783,0.6425543 -1.4184783,1.4225545 0,0.78 0.6384783,1.4184784 1.4184783,1.4184784 0.78,0 1.4225543,-0.6384784 1.4225543,-1.4184784 0,-0.7800002 -0.6425543,-1.4225545 -1.4225543,-1.4225545 z m 4.9361418,4.7160329 c -0.387159,0.579128 -0.84606,1.109077 -1.40625,1.524456 -0.3,0.22 -0.3775,0.631957 -0.1875,0.961957 0.22,0.39 0.728315,0.488261 1.088315,0.228261 0.438174,-0.322866 0.826135,-0.698796 1.177989,-1.100544 a 7.0169487,8.1355924 0 0 1 -0.672554,-1.61413 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="m 21.045878,10.964692 v 0 q 0,1.36304 -0.84885,2.1693 -0.84886,0.80626 -2.32751,0.80626 v 0 q -1.29001,0 -2.06585,-0.58112 -0.77583,-0.58112 -0.95838,-1.6825 v 0 l 1.70988,-0.13995 q 0.13387,0.54765 0.47462,0.79713 0.34076,0.24949 0.85799,0.24949 v 0 q 0.63892,0 1.01923,-0.4077 0.38031,-0.40769 0.38031,-1.1744 v 0 q 0,-0.67543 -0.35901,-1.0800798 -0.35902,-0.40465 -1.00402,-0.40465 v 0 q -0.71195,0 -1.16223,0.5537298 v 0 h -1.66729 l 0.29817,-4.8253905 h 5.15397 v 1.27176 h -3.6023 l -0.13996,2.1662507 q 0.62067,-0.5476397 1.55167,-0.5476397 v 0 q 1.22308,0 1.95632,0.7606197 0.73324,0.76062 0.73324,2.0688898 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_6_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_6_hotspot.xml
new file mode 100644
index 0000000..9b5e28e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_6_hotspot.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="2.5dp"
+ android:insetRight="2.5dp">
+ <vector
+ android:width="22.0dp"
+ android:height="18.0dp"
+ android:viewportWidth="22.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:pathData="m 9.2771788,1.842391 c -0.5341993,-0.05549 -1.0854891,-0.0556 -1.6467391,0.0081 -3.4399999,0.39 -6.2098912,3.2184785 -6.5298912,6.6684783 -0.26000004,2.6099997 0.8777717,5.1510867 2.9877717,6.7010867 0.36,0.26 0.8623912,0.151739 1.0923913,-0.228261 0.1899999,-0.32 0.098424,-0.741957 -0.1915761,-0.961957 -1.7,-1.259997 -2.7078261,-3.380975 -2.3478261,-5.7309751 C 3.0413094,5.698863 5.2101681,3.620113 7.8301679,3.3301128 10.338407,3.0436568 12.553222,4.3446002 13.675277,6.3423412 A 7.0169487,8.1355924 0 0 1 14.478266,4.8097325 C 13.262879,3.1798315 11.402845,2.063138 9.2771788,1.842341 Z M 8.4986462,4.9605977 c -0.18,0 -0.3498912,0.00854 -0.5298912,0.028533 -1.86,0.23 -3.3884784,1.7125 -3.6684783,3.5624999 -0.2300001,1.5200004 0.351413,2.9092944 1.361413,3.8192934 0.34,0.3 0.8764674,0.228804 1.0964673,-0.171195 0.1699993,-0.3 0.1010337,-0.668587 -0.1589677,-0.888586 C 5.8191898,10.611142 5.4791354,9.5390216 5.7391354,8.5190215 c 0.25,-1.0199998 1.0425001,-1.8084238 2.0624999,-2.0584238 1.5200001,-0.38 3.0583697,0.5384239 3.4483697,2.0584238 0.06,0.2300002 0.08967,0.462935 0.08967,0.6929351 0,0.8400004 -0.361577,1.5791854 -0.941577,2.0991854 -0.25,0.23 -0.328968,0.600814 -0.158968,0.900814 0.22,0.38 0.739783,0.489729 1.059783,0.199729 0.92,-0.81 1.451087,-1.979728 1.451087,-3.1997284 0,-2.3500003 -1.901359,-4.2513589 -4.2513588,-4.2513589 z m 0,2.8288044 c -0.78,0 -1.4184783,0.6425543 -1.4184783,1.4225545 0,0.78 0.6384783,1.4184784 1.4184783,1.4184784 0.78,0 1.4225543,-0.6384784 1.4225543,-1.4184784 0,-0.7800002 -0.6425543,-1.4225545 -1.4225543,-1.4225545 z m 4.9361418,4.7160329 c -0.387159,0.579128 -0.84606,1.109077 -1.40625,1.524456 -0.3,0.22 -0.3775,0.631957 -0.1875,0.961957 0.22,0.39 0.728315,0.488261 1.088315,0.228261 0.438174,-0.322866 0.826135,-0.698796 1.177989,-1.100544 a 7.0169487,8.1355924 0 0 1 -0.672554,-1.61413 z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="m 21.149959,10.98593 v 0 q 0,1.31751 -0.814213,2.067022 -0.814212,0.749513 -2.248777,0.749513 v 0 q -1.609039,0 -2.471717,-1.0218 -0.862677,-1.021801 -0.862677,-3.0302636 v 0 q 0,-2.2075569 0.875601,-3.3230469 0.875602,-1.11549 2.504027,-1.11549 v 0 q 1.156698,0 1.825516,0.462592 0.668817,0.462591 0.946684,1.434619 v 0 l -1.712431,0.216656 q -0.245556,-0.813927 -1.098541,-0.813927 v 0 q -0.730207,0 -1.147005,0.661682 -0.4168,0.661682 -0.4168,2.008467 v 0 q 0.29079,-0.439168 0.807751,-0.673393 0.51696,-0.234223 1.169623,-0.234223 v 0 q 1.221318,0 1.932139,0.702671 0.71082,0.7026709 0.71082,1.9089215 z m -1.822285,0.04685 v 0 q 0,-0.70267 -0.358641,-1.0744998 -0.358642,-0.3718297 -0.985456,-0.3718297 v 0 q -0.600966,0 -0.962838,0.3484077 -0.361873,0.3484068 -0.361873,0.9222548 v 0 q 0,0.720242 0.378028,1.191617 0.378026,0.471375 0.991917,0.471375 v 0 q 0.61389,0 0.956377,-0.395255 0.342486,-0.395254 0.342486,-1.09207 z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
+ </vector>
+</inset>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
old mode 100644
new mode 100755
index 1bfc4c0..7e5009a
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -26,6 +26,15 @@
<include layout="@layout/keyguard_indication_area_overlay" />
+ <include layout="@layout/keyguard_emergency_carrier_area"
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="70dp"
+ android:orientation="vertical"
+ android:layout_gravity="bottom|center_horizontal"
+ android:gravity="center_horizontal" />
+
<FrameLayout
android:id="@+id/preview_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index bfd079b..9b93e5c 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
+/*
+ * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+*/
+/*
**
** Copyright 2011, The Android Open Source Project
**
@@ -62,7 +67,7 @@
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical">
+ >
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
android:layout_height="@dimen/qs_header_mobile_icon_size"
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index 42d541e3..23b90de 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -22,15 +22,19 @@
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:gravity="center_vertical" >
-
+ android:gravity="center_vertical">
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/mobile_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal" >
-
+ <ImageView
+ android:id="@+id/mobile_volte"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="gone"
+ android:paddingEnd="2dp"/>
<FrameLayout
android:id="@+id/inout_container"
android:layout_height="17dp"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index efcc2c4..5561f43 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -135,8 +135,8 @@
<integer name="quick_settings_brightness_dialog_short_timeout">2000</integer>
<integer name="quick_settings_brightness_dialog_long_timeout">4000</integer>
- <!-- Show indicator for Wifi on but not connected. -->
- <bool name="config_showWifiIndicatorWhenEnabled">false</bool>
+ <!-- Should "LTE"/"4G" be shown instead of "LTE+"/"4G+" when on NETWORK_TYPE_LTE_CA? -->
+ <bool name="config_hideLtePlus">false</bool>
<!-- The number of milliseconds before the heads up notification auto-dismisses. -->
<integer name="heads_up_notification_decay">5000</integer>
@@ -337,7 +337,7 @@
<bool name="config_enableNotificationShadeDrag">true</bool>
<!-- Whether to show activity indicators in the status bar -->
- <bool name="config_showActivity">false</bool>
+ <bool name="config_showActivity">true</bool>
<!-- Whether or not the button to clear all notifications will be shown. -->
<bool name="config_enableNotificationsClearAll">true</bool>
@@ -375,6 +375,7 @@
the other notifications need to be manually expanded by the user. -->
<bool name="config_alwaysExpandNonGroupedNotifications">false</bool>
+
<!-- Whether or not an expandable notification can be manually expanded or collapsed by the
user. Grouped notifications are still expandable even if this value is false. -->
<bool name="config_enableNonGroupedNotificationExpand">true</bool>
@@ -415,6 +416,9 @@
<item>120</item>
</integer-array>
+
+
+
<!-- Smart replies in notifications: Whether smart replies in notifications are enabled. -->
<bool name="config_smart_replies_in_notifications_enabled">true</bool>
diff --git a/packages/SystemUI/res/values/config_qti.xml b/packages/SystemUI/res/values/config_qti.xml
new file mode 100644
index 0000000..82c1a47
--- /dev/null
+++ b/packages/SystemUI/res/values/config_qti.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<resources>
+ <bool name="kg_hide_emgcy_btn_when_oos">false</bool>
+ <bool name="config_showEmergencyButton">false</bool>
+ <bool name="config_show_customize_carrier_name">false</bool>
+ <bool name="config_showRsrpSignalLevelforLTE">false</bool>
+ <bool name="config_alwaysShowTypeIcon">false</bool>
+ <bool name="config_hideNoInternetState">false</bool>
+ <bool name="config_display_volte">false</bool>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 14371fe..140dfbc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -757,7 +757,7 @@
<dimen name="keyguard_lock_width">42dp</dimen>
<dimen name="keyguard_lock_padding">20dp</dimen>
- <dimen name="keyguard_indication_margin_bottom">40dp</dimen>
+ <dimen name="keyguard_indication_margin_bottom">125dp</dimen>
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
diff --git a/packages/SystemUI/res/values/strings_qti.xml b/packages/SystemUI/res/values/strings_qti.xml
new file mode 100644
index 0000000..d89e092
--- /dev/null
+++ b/packages/SystemUI/res/values/strings_qti.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string-array name="origin_carrier_names"></string-array>
+
+ <string-array name="locale_carrier_names"></string-array>
+
+ <!-- config 2G/3G/4G RAT strings for carriers -->
+ <string name="config_rat_unknown" translatable="false">""</string>
+ <string name="config_rat_2g" translatable="false">2G</string>
+ <string name="config_rat_3g" translatable="false">3G</string>
+ <string name="config_rat_4g" translatable="false">4G</string>
+
+ <!-- Content description of the data connection type 5G Basic. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_5g_basic" translate="false">5GBasic</string>
+
+ <!-- Content description of the data connection type 5G UWB. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_5g_uwb" translate="false">5GUWB</string>
+
+ <!-- Content description of the data connection type 5G stand alone. [CHAR LIMIT=NONE] -->
+ <string name="data_connection_5g_sa" translate="false">5GSA</string>
+
+</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 46b4c6b..7cc16cf 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -44,6 +44,8 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.policy.FiveGServiceClient;
+import com.android.systemui.statusbar.policy.FiveGServiceClient.FiveGServiceState;
import java.util.List;
import java.util.Objects;
@@ -72,6 +74,7 @@
private Context mContext;
private CharSequence mSeparator;
private WakefulnessLifecycle mWakefulnessLifecycle;
+ private FiveGServiceClient mFiveGServiceClient;
private final WakefulnessLifecycle.Observer mWakefulnessObserver =
new WakefulnessLifecycle.Observer() {
@Override
@@ -267,11 +270,15 @@
protected void updateCarrierText() {
boolean allSimsMissing = true;
boolean anySimReadyAndInService = false;
+ boolean missingSimsWithSubs = false;
+ boolean showCustomizeName = getContext().getResources().getBoolean(
+ com.android.systemui.R.bool.config_show_customize_carrier_name);
CharSequence displayText = null;
List<SubscriptionInfo> subs = getSubscriptionInfo();
final int numSubs = subs.size();
final int[] subsIds = new int[numSubs];
+ if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs);
// This array will contain in position i, the index of subscription in slot ID i.
// -1 if no subscription in that slot
final int[] subOrderBySlot = new int[mSimSlotsNumber];
@@ -288,6 +295,9 @@
subOrderBySlot[subs.get(i).getSimSlotIndex()] = i;
IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
CharSequence carrierName = subs.get(i).getCarrierName();
+ if ( showCustomizeName ) {
+ carrierName = getCustomizeCarrierName(carrierName, subs.get(i));
+ }
CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
if (DEBUG) {
Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName);
@@ -303,8 +313,8 @@
// Wi-Fi is disassociated or disabled
if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
|| (mWifiManager.isWifiEnabled()
- && mWifiManager.getConnectionInfo() != null
- && mWifiManager.getConnectionInfo().getBSSID() != null)) {
+ && mWifiManager.getConnectionInfo() != null
+ && mWifiManager.getConnectionInfo().getBSSID() != null)) {
if (DEBUG) {
Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss);
}
@@ -323,7 +333,7 @@
// "No SIM card"
// Grab the first subscripton, because they all should contain the emergency text,
// described above.
- displayText = makeCarrierStringOnEmergencyCapable(
+ displayText = makeCarrierStringOnEmergencyCapable(
getMissingSimMessage(), subs.get(0).getCarrierName());
} else {
// We don't have a SubscriptionInfo to get the emergency calls only from.
@@ -350,7 +360,7 @@
text = concatenate(plmn, spn, mSeparator);
}
}
- displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
+ displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text);
}
}
@@ -649,4 +659,114 @@
*/
default void finishedWakingUp() {};
}
+
+ private String getCustomizeCarrierName(CharSequence originCarrierName,
+ SubscriptionInfo sub) {
+ StringBuilder newCarrierName = new StringBuilder();
+ int networkType = getNetworkType(sub.getSubscriptionId());
+ String networkClass = networkClassToString(TelephonyManager.getNetworkClass(networkType));
+
+ String fiveGNetworkClass = get5GNetworkClass(sub);
+ if ( fiveGNetworkClass != null ) {
+ networkClass = fiveGNetworkClass;
+ }
+
+ if (!TextUtils.isEmpty(originCarrierName)) {
+ String[] names = originCarrierName.toString().split(mSeparator.toString(), 2);
+ for (int j = 0; j < names.length; j++) {
+ names[j] = getLocalString(
+ names[j], com.android.systemui.R.array.origin_carrier_names,
+ com.android.systemui.R.array.locale_carrier_names);
+ if (!TextUtils.isEmpty(names[j])) {
+ if (!TextUtils.isEmpty(networkClass)) {
+ names[j] = new StringBuilder().append(names[j]).append(" ")
+ .append(networkClass).toString();
+ }
+ if (j > 0 && names[j].equals(names[j - 1])) {
+ continue;
+ }
+ if (j > 0) {
+ newCarrierName.append(mSeparator);
+ }
+ newCarrierName.append(names[j]);
+ }
+ }
+ }
+ return newCarrierName.toString();
+ }
+
+ private int getNetworkType(int subId) {
+ int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
+ if (ss != null && (ss.getDataRegState() == ServiceState.STATE_IN_SERVICE
+ || ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE)) {
+ networkType = ss.getDataNetworkType();
+ if (networkType == TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+ networkType = ss.getVoiceNetworkType();
+ }
+ }
+ return networkType;
+ }
+
+ private String networkClassToString (int networkClass) {
+ final int[] classIds = {
+ com.android.systemui.R.string.config_rat_unknown,
+ com.android.systemui.R.string.config_rat_2g,
+ com.android.systemui.R.string.config_rat_3g,
+ com.android.systemui.R.string.config_rat_4g };
+ String classString = null;
+ if (networkClass < classIds.length) {
+ classString = getContext().getResources().getString(classIds[networkClass]);
+ }
+ return (classString == null) ? "" : classString;
+ }
+
+ /**
+ * parse the string to current language.
+ *
+ * @param originalString original string
+ * @param originNamesId the id of the original string array.
+ * @param localNamesId the id of the local string keys.
+ * @return local language string
+ */
+ private String getLocalString(String originalString,
+ int originNamesId, int localNamesId) {
+ String[] origNames = getContext().getResources().getStringArray(originNamesId);
+ String[] localNames = getContext().getResources().getStringArray(localNamesId);
+ for (int i = 0; i < origNames.length; i++) {
+ if (origNames[i].equalsIgnoreCase(originalString)) {
+ return localNames[i];
+ }
+ }
+ return originalString;
+ }
+
+ private String get5GNetworkClass(SubscriptionInfo sub) {
+ int slotIndex = sub.getSimSlotIndex();
+ int subId = sub.getSubscriptionId();
+
+ if ( mFiveGServiceClient == null ) {
+ mFiveGServiceClient = FiveGServiceClient.getInstance(mContext);
+ mFiveGServiceClient.registerCallback(mCallback);
+ }
+ FiveGServiceState fiveGServiceState =
+ mFiveGServiceClient.getCurrentServiceState(slotIndex);
+ if ( fiveGServiceState.isNrIconTypeValid() && isDataRegisteredOnLte(subId)) {
+ return mContext.getResources().getString(R.string.data_connection_5g);
+ }
+
+ return null;
+ }
+
+ private boolean isDataRegisteredOnLte(int subId) {
+ TelephonyManager telephonyManager = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ int dataType = telephonyManager.getDataNetworkType(subId);
+ if ( dataType == TelephonyManager.NETWORK_TYPE_LTE ||
+ dataType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ return true;
+ }else{
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 1c30762..733d081 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -28,8 +28,10 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.telecom.TelecomManager;
+import android.telephony.ServiceState;
import android.util.AttributeSet;
import android.util.Slog;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -41,6 +43,7 @@
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.util.EmergencyDialerConstants;
/**
@@ -75,6 +78,11 @@
public void onPhoneStateChanged(int phoneState) {
updateEmergencyCallButton();
}
+
+ @Override
+ public void onServiceStateChanged(int subId, ServiceState state) {
+ updateEmergencyCallButton();
+ }
};
private boolean mLongPressWasDragged;
@@ -195,7 +203,7 @@
}
}
- private void updateEmergencyCallButton() {
+ public void updateEmergencyCallButton() {
boolean visible = false;
if (mIsVoiceCapable) {
// Emergency calling requires voice capability.
@@ -208,8 +216,14 @@
// Some countries can't handle emergency calls while SIM is locked.
visible = mEnableEmergencyCallWhileSimLocked;
} else {
- // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
- visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
+ // Show if there is a secure screen (pin/pattern/SIM pin/SIM puk) or config set
+ visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()) ||
+ mContext.getResources().getBoolean(R.bool.config_showEmergencyButton);
+ }
+
+ if (mContext.getResources().getBoolean(R.bool.kg_hide_emgcy_btn_when_oos)) {
+ KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
+ visible = visible && !monitor.isOOS();
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index caee8cc..6f955f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -200,6 +200,7 @@
boolean isValidPassword) {
boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
if (matched) {
+ mLockPatternUtils.sanitizePassword();
mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
mDismissing = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
old mode 100644
new mode 100755
index 0340904..9ade1cf4
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -25,7 +25,7 @@
* Turns on debugging information for the whole Keyguard. This is very verbose and should only
* be used temporarily for debugging.
*/
- public static final boolean DEBUG = false;
+ public static final boolean DEBUG = true;
public static final boolean DEBUG_SIM_STATES = true;
public static final boolean DEBUG_BIOMETRIC_WAKELOCK = true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 9eb168a..ef48a53 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -348,6 +348,7 @@
boolean isValidPattern) {
boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
if (matched) {
+ mLockPatternUtils.sanitizePassword();
mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
old mode 100644
new mode 100755
index 9c0a71c..96bd2bb
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -63,6 +63,7 @@
private AlertDialog mRemainingAttemptsDialog;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
+ private int mSlotId;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
@@ -103,6 +104,7 @@
}
private void setLockedSimMessage() {
+ mSlotId = SubscriptionManager.getSlotIndex(mSubId) + 1;
boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
int count = TelephonyManager.getDefault().getSimCount();
Resources rez = getResources();
@@ -178,10 +180,18 @@
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
- msgId = isDefault ? R.plurals.kg_password_default_pin_message :
- R.plurals.kg_password_wrong_pin_code;
- displayMessage = getContext().getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ int count = TelephonyManager.getDefault().getSimCount();
+ if ( count > 1 ) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message_multi_sim :
+ R.plurals.kg_password_wrong_pin_code_multi_sim;
+ displayMessage = getContext().getResources()
+ .getQuantityString(msgId, attemptsRemaining, mSlotId, attemptsRemaining);
+ }else {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
+ displayMessage = getContext().getResources()
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ }
} else {
msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
displayMessage = getContext().getString(msgId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
old mode 100644
new mode 100755
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 27410be..e73a27b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2326,7 +2326,17 @@
mServiceStates.put(subId, serviceState);
- callbacksRefreshCarrierInfo();
+ // The upstream method (callbacksRefreshCarrierInfo) does not subId or
+ // serviceState as input. Thus onServiceStateChanged cannot be called
+ // from that new method. For now, re-use the same logic as before here
+ // instead of a call to callbacksRefreshCarrierInfo.
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onRefreshCarrierInfo();
+ cb.onServiceStateChanged(subId, serviceState);
+ }
+ }
}
public boolean isKeyguardVisible() {
@@ -2634,6 +2644,36 @@
}
};
+ public boolean isOOS()
+ {
+ boolean ret = true;
+ int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+
+ for (int phoneId = 0; phoneId < phoneCount; phoneId++) {
+ int[] subId = SubscriptionManager.getSubId(phoneId);
+ if (subId != null && subId.length >= 1) {
+ if (DEBUG) Log.d(TAG, "slot id:" + phoneId + " subId:" + subId[0]);
+ ServiceState state = mServiceStates.get(subId[0]);
+ if (state != null) {
+ if (state.isEmergencyOnly())
+ ret = false;
+ if ((state.getVoiceRegState() != ServiceState.STATE_OUT_OF_SERVICE)
+ && (state.getVoiceRegState() != ServiceState.STATE_POWER_OFF))
+ ret = false;
+ if (DEBUG) {
+ Log.d(TAG, "is emergency: " + state.isEmergencyOnly());
+ Log.d(TAG, "voice state: " + state.getVoiceRegState());
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "state is NULL");
+ }
+ }
+ }
+
+ if (DEBUG) Log.d(TAG, "is Emergency supported: " + ret);
+ return ret;
+ }
+
/**
* @return true if and only if the state has changed for the specified {@code slotId}
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 0fef755..6440354 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -20,6 +20,7 @@
import android.hardware.biometrics.BiometricSourceType;
import android.media.AudioManager;
import android.os.SystemClock;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicyConstants;
@@ -139,6 +140,13 @@
public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { }
/**
+ * Called when the sevice state changes.
+ * @param subId
+ * @param serviceState
+ */
+ public void onServiceStateChanged(int subId, ServiceState state) { }
+
+ /**
* Called when the user's info changed.
*/
public void onUserInfoChanged(int userId) { }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 411bf9a..800d021 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1253,7 +1253,8 @@
if (mOccluded != isOccluded) {
mOccluded = isOccluded;
mUpdateMonitor.setKeyguardOccluded(isOccluded);
- mStatusBarKeyguardViewManager.setOccluded(isOccluded, animate
+ mStatusBarKeyguardViewManager.setOccluded(isOccluded,
+ (Dependency.get(KeyguardUpdateMonitor.class).isSimPinSecure()?false:animate)
&& mDeviceInteractive);
adjustStatusBarLocked();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 5742787..8fe687b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -242,6 +242,7 @@
public void setMobileDataIndicators(NetworkController.IconState statusIcon,
NetworkController.IconState qsIcon, int statusType,
int qsType, boolean activityIn, boolean activityOut,
+ int volteIcon,
String typeContentDescription,
String description, boolean isWide, int subId, boolean roaming) {
int slotIndex = getSlotIndex(subId);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2060059..4c81348 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -173,11 +173,12 @@
mFooter = new QSSecurityFooter(this, context);
addView(mFooter.getView());
- updateResources();
-
mBrightnessController = new BrightnessController(getContext(),
findViewById(R.id.brightness_slider));
mDumpController = dumpController;
+
+ updateResources();
+
mPluginManager = pluginManager;
if (mPluginManager != null && Settings.System.getInt(
mContext.getContentResolver(), "npv_plugin_flag", 0) == 2) {
@@ -428,6 +429,9 @@
updatePageIndicator();
+ for (TileRecord r : mRecords) {
+ r.tile.clearState();
+ }
if (mListening) {
refreshAllTiles();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 0e813d1..d4e9fdf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.media.MediaRouter.RouteInfo;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.util.Log;
@@ -67,6 +68,7 @@
private final ActivityStarter mActivityStarter;
private Dialog mDialog;
private boolean mWifiConnected;
+ private static final String WFD_ENABLE = "persist.debug.wfd.enable";
@Inject
public CastTile(QSHost host, CastController castController,
@@ -250,10 +252,17 @@
NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
String description, boolean isTransient, String statusLabel) {
// statusIcon.visible has the connected status information
- boolean enabledAndConnected = enabled && qsIcon.visible;
- if (enabledAndConnected != mWifiConnected) {
- mWifiConnected = enabledAndConnected;
- refreshState();
+ if(SystemProperties.getBoolean(WFD_ENABLE, false)) {
+ if(enabled != mWifiConnected) {
+ mWifiConnected = enabled;
+ refreshState();
+ }
+ } else {
+ boolean enabledAndConnected = enabled && qsIcon.visible;
+ if (enabledAndConnected != mWifiConnected) {
+ mWifiConnected = enabledAndConnected;
+ refreshState();
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 22470c7..e32fc32 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -27,6 +27,7 @@
import android.service.quicksettings.Tile;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -49,11 +50,13 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.util.Utils;
import javax.inject.Inject;
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTileImpl<SignalState> {
+ private static final String LOG_TAG = "CellularTile";
private static final String ENABLE_SETTINGS_DATA_PLAN = "enable.settings.data.plan";
private final NetworkController mController;
@@ -255,8 +258,9 @@
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId, boolean roaming) {
+ int qsType, boolean activityIn, boolean activityOut, int volteIcon,
+ String typeContentDescription, String description, boolean isWide,
+ int subId, boolean roaming) {
if (qsIcon == null) {
// Not data sim, don't display.
return;
@@ -288,12 +292,20 @@
}
}
- static Intent getCellularSettingIntent() {
- Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+ private Intent getCellularSettingIntent() {
+ Intent intent = new Intent("codeaurora.intent.action.MOBILE_NETWORK_SETTINGS");
int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
- if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- intent.putExtra(Settings.EXTRA_SUB_ID,
- SubscriptionManager.getDefaultDataSubscriptionId());
+
+ if (mContext != null && intent.resolveActivity(mContext.getPackageManager()) != null) {
+ intent.putExtra(Utils.EXTRA_SLOT_ID, SubscriptionManager.getSlotIndex(dataSub));
+ Log.d(LOG_TAG, "Using vendor network settings for sub: " + dataSub);
+ } else {
+ intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+ if (dataSub != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ intent.putExtra(Settings.EXTRA_SUB_ID,
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ }
+ Log.d(LOG_TAG, "Using default network settings for sub: " + dataSub);
}
return intent;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 16a3975..337bb38 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -18,7 +18,9 @@
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.net.wifi.WifiManager;
import android.os.UserManager;
import android.service.quicksettings.Tile;
import android.widget.Switch;
@@ -39,12 +41,16 @@
"com.android.settings", "com.android.settings.TetherSettings"));
private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
+ private final Icon mWifi4EnabledStatic = ResourceIcon.get(R.drawable.ic_wifi_4_hotspot);
+ private final Icon mWifi5EnabledStatic = ResourceIcon.get(R.drawable.ic_wifi_5_hotspot);
+ private final Icon mWifi6EnabledStatic = ResourceIcon.get(R.drawable.ic_wifi_6_hotspot);
private final HotspotController mHotspotController;
private final DataSaverController mDataSaverController;
private final HotspotAndDataSaverCallbacks mCallbacks = new HotspotAndDataSaverCallbacks();
private boolean mListening;
+ private WifiManager mWifiManager;
@Inject
public HotspotTile(QSHost host, HotspotController hotspotController,
@@ -54,6 +60,7 @@
mDataSaverController = dataSaverController;
mHotspotController.observe(this, mCallbacks);
mDataSaverController.observe(this, mCallbacks);
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}
@Override
@@ -133,6 +140,15 @@
if (state.isTransient) {
state.icon = ResourceIcon.get(
com.android.internal.R.drawable.ic_hotspot_transient_animation);
+ } else if (state.value) {
+ int generation = mWifiManager.getSoftApWifiGeneration();
+ if (generation == WifiManager.WIFI_GENERATION_6) {
+ state.icon = mWifi6EnabledStatic;
+ } else if (generation == WifiManager.WIFI_GENERATION_5) {
+ state.icon = mWifi5EnabledStatic;
+ } else if (generation == WifiManager.WIFI_GENERATION_4) {
+ state.icon = mWifi4EnabledStatic;
+ }
}
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 689d161..6311a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -27,6 +27,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -60,6 +61,8 @@
private int mVisibleState = -1;
private DualToneHandler mDualToneHandler;
+ private ImageView mVolte;
+
public static StatusBarMobileView fromContext(Context context, String slot) {
LayoutInflater inflater = LayoutInflater.from(context);
StatusBarMobileView v = (StatusBarMobileView)
@@ -109,6 +112,7 @@
mIn = findViewById(R.id.mobile_in);
mOut = findViewById(R.id.mobile_out);
mInoutContainer = findViewById(R.id.inout_container);
+ mVolte = findViewById(R.id.mobile_volte);
mMobileDrawable = new SignalDrawable(getContext());
mMobile.setImageDrawable(mMobileDrawable);
@@ -143,6 +147,18 @@
if (requestLayout) {
requestLayout();
}
+
+ if ( needFixVisibleState() ) {
+ Log.d(TAG, "fix VisibleState width=" + getWidth() + " height=" + getHeight());
+ mVisibleState = STATE_ICON;
+ setVisibility(View.VISIBLE);
+ requestLayout();
+ }else if (needFixInVisibleState() ) {
+ Log.d(TAG, "fix InVisibleState width=" + getWidth() + " height=" + getHeight());
+ mVisibleState = -1;
+ setVisibility(View.INVISIBLE);
+ requestLayout();
+ }
}
private void initViewState() {
@@ -167,6 +183,12 @@
mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
mInoutContainer.setVisibility((mState.activityIn || mState.activityOut)
? View.VISIBLE : View.GONE);
+ if (mState.volteId > 0 ) {
+ mVolte.setImageResource(mState.volteId);
+ mVolte.setVisibility(View.VISIBLE);
+ }else {
+ mVolte.setVisibility(View.GONE);
+ }
}
private boolean updateState(MobileIconState state) {
@@ -198,6 +220,15 @@
mInoutContainer.setVisibility((state.activityIn || state.activityOut)
? View.VISIBLE : View.GONE);
+ if (mState.volteId != state.volteId) {
+ if (state.volteId != 0) {
+ mVolte.setImageResource(state.volteId);
+ mVolte.setVisibility(View.VISIBLE);
+ } else {
+ mVolte.setVisibility(View.GONE);
+ }
+ }
+
needsLayout |= state.roaming != mState.roaming
|| state.activityIn != mState.activityIn
|| state.activityOut != mState.activityOut;
@@ -217,6 +248,7 @@
mIn.setImageTintList(color);
mOut.setImageTintList(color);
mMobileType.setImageTintList(color);
+ mVolte.setImageTintList(color);
mMobileRoaming.setImageTintList(color);
mDotView.setDecorColor(tint);
mDotView.setIconColor(tint, false);
@@ -242,6 +274,7 @@
mIn.setImageTintList(list);
mOut.setImageTintList(list);
mMobileType.setImageTintList(list);
+ mVolte.setImageTintList(list);
mMobileRoaming.setImageTintList(list);
mDotView.setDecorColor(color);
}
@@ -290,6 +323,22 @@
return mState;
}
+ private boolean needFixVisibleState() {
+ if ( mState.visible && (getVisibility() != View.VISIBLE) ) {
+ return true;
+ }else {
+ return false;
+ }
+ }
+
+ private boolean needFixInVisibleState() {
+ if ( !mState.visible && (getVisibility() == View.VISIBLE)) {
+ return true;
+ }else {
+ return false;
+ }
+ }
+
@Override
public String toString() {
return "StatusBarMobileView(slot=" + mSlot + " state=" + mState + ")";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 9bc0ca4..2364313 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -33,6 +33,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewStub;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+
import android.widget.SeekBar;
import android.widget.TextView;
@@ -72,6 +74,7 @@
private View mSeekBarView;
private Context mContext;
private MetricsLogger mMetricsLogger;
+ private boolean mOnPreDrawListenerRegistered = false;
private boolean mIsViewVisible;
@VisibleForTesting
@@ -161,6 +164,16 @@
}
};
+ private OnPreDrawListener mPreDrawListener = new OnPreDrawListener(){
+ @Override
+ public boolean onPreDraw(){
+ removeOnPreDrawListener();
+ mHandler.removeCallbacks(mOnUpdateTimerTick);
+ mHandler.postDelayed(mOnUpdateTimerTick,PROGRESS_UPDATE_INTERVAL);
+ return true;
+ }
+ };
+
protected NotificationMediaTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -277,13 +290,23 @@
private void startTimer() {
clearTimer();
if (mIsViewVisible) {
- mSeekBarTimer = new Timer(true /* isDaemon */);
- mSeekBarTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- mHandler.post(mOnUpdateTimerTick);
- }
- }, 0, PROGRESS_UPDATE_INTERVAL);
+ addOnPreDrawListener();
+ }
+ }
+
+
+ private void addOnPreDrawListener() {
+ if ( !mOnPreDrawListenerRegistered ) {
+ mOnPreDrawListenerRegistered = true;
+ mSeekBarView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ }
+ }
+
+ private void removeOnPreDrawListener() {
+ if ( mOnPreDrawListenerRegistered ) {
+ mSeekBarView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
+ mHandler.postDelayed(mOnUpdateTimerTick, PROGRESS_UPDATE_INTERVAL);
+ mOnPreDrawListenerRegistered = false;
}
}
@@ -293,6 +316,7 @@
mSeekBarTimer.purge();
mSeekBarTimer = null;
}
+ removeOnPreDrawListener();
}
@Override
@@ -344,6 +368,9 @@
PlaybackState playbackState = mMediaController.getPlaybackState();
if (playbackState != null) {
updatePlaybackUi(playbackState);
+ if ( playbackState.getState() == PlaybackState.STATE_PLAYING ) {
+ addOnPreDrawListener();
+ }
} else {
clearTimer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d95d2b7..99da47a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -64,6 +64,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.EmergencyCarrierArea;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.ActivityIntentHelper;
@@ -117,6 +118,8 @@
private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
+ private EmergencyCarrierArea mEmergencyCarrierArea;
+
private final boolean mShowLeftAffordance;
private final boolean mShowCameraAffordance;
@@ -233,6 +236,7 @@
mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext),
new ActivityIntentHelper(mContext));
mPreviewContainer = findViewById(R.id.preview_container);
+ mEmergencyCarrierArea = (EmergencyCarrierArea) findViewById(R.id.keyguard_selector_fade_container);
mOverlayContainer = findViewById(R.id.overlay_container);
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.left_button);
@@ -737,8 +741,10 @@
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
+ mEmergencyCarrierArea.setVisibility(INVISIBLE);
} else {
mOverlayContainer.setVisibility(VISIBLE);
+ mEmergencyCarrierArea.setVisibility(VISIBLE);
if (animate) {
startFinishDozeAnimation();
}
@@ -766,6 +772,7 @@
mLeftAffordanceView.setAlpha(alpha);
mRightAffordanceView.setAlpha(alpha);
mIndicationArea.setAlpha(alpha);
+ mEmergencyCarrierArea.setAlpha(alpha);
}
private class DefaultLeftButton implements IntentButton {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
old mode 100644
new mode 100755
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e8e5e1f..b3051b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -48,7 +48,9 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import android.util.BoostFramework;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -114,6 +116,11 @@
private final VibratorHelper mVibratorHelper;
/**
+ * For PanelView fling perflock call
+ */
+ private BoostFramework mPerf = null;
+
+ /**
* Whether an instant expand request is currently pending and we are just waiting for layout.
*/
private boolean mInstantExpanding;
@@ -223,6 +230,8 @@
mVibratorHelper = Dependency.get(VibratorHelper.class);
mVibrateOnOpening = mContext.getResources().getBoolean(
R.bool.config_vibrateOnIconAnimation);
+
+ mPerf = new BoostFramework();
}
protected void loadDimens() {
@@ -786,16 +795,26 @@
animator.setDuration(mFixedDuration);
}
}
+ if (mPerf != null) {
+ String currentPackage = mContext.getPackageName();
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST, currentPackage, -1, BoostFramework.Scroll.PANEL_VIEW);
+ }
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
public void onAnimationCancel(Animator animation) {
+ if (mPerf != null) {
+ mPerf.perfLockRelease();
+ }
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
+ if (mPerf != null) {
+ mPerf.perfLockRelease();
+ }
if (clearAllExpandHack && !mCancelled) {
setExpandedHeightInternal(getMaxPanelHeight());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
old mode 100644
new mode 100755
index 294111c..fabd67e
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
+import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -137,6 +138,7 @@
private BluetoothController mBluetooth;
private AlarmManager.AlarmClockInfo mNextAlarm;
+ private WifiManager mWifiManager;
public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {
mContext = context;
@@ -184,6 +186,7 @@
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+ filter.addAction(Intent.ACTION_BOOT_COMPLETED);
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// listen for user / profile change.
@@ -216,11 +219,6 @@
mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
mIconController.setIconVisibility(mSlotCast, false);
- // hotspot
- mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
- mContext.getString(R.string.accessibility_status_bar_hotspot));
- mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
-
// managed profile
mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
mContext.getString(R.string.accessibility_managed_profile));
@@ -511,6 +509,7 @@
private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
@Override
public void onHotspotChanged(boolean enabled, int numDevices) {
+ updateHotspotIcon();
mIconController.setIconVisibility(mSlotHotspot, enabled);
}
};
@@ -681,6 +680,9 @@
case AudioManager.ACTION_HEADSET_PLUG:
updateHeadsetPlug(intent);
break;
+ case Intent.ACTION_BOOT_COMPLETED:
+ handleBootCompleted();
+ break;
}
}
};
@@ -692,4 +694,28 @@
mIconController.setIconVisibility(mSlotCast, false);
}
};
+
+ private void updateHotspotIcon() {
+ int generation = mWifiManager.getSoftApWifiGeneration();
+ if (generation == WifiManager.WIFI_GENERATION_6) {
+ mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_wifi_6_hotspot,
+ mContext.getString(R.string.accessibility_status_bar_hotspot));
+ } else if (generation == WifiManager.WIFI_GENERATION_5) {
+ mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_wifi_5_hotspot,
+ mContext.getString(R.string.accessibility_status_bar_hotspot));
+ } else if (generation == WifiManager.WIFI_GENERATION_4) {
+ mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_wifi_4_hotspot,
+ mContext.getString(R.string.accessibility_status_bar_hotspot));
+ } else {
+ mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
+ mContext.getString(R.string.accessibility_status_bar_hotspot));
+ }
+ }
+
+ private void handleBootCompleted() {
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ // hotspot
+ updateHotspotIcon();
+ mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b8adfea..1108061 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3885,6 +3885,7 @@
@Override
public void onScreenTurnedOff() {
+ updateDozing();
mFalsingManager.onScreenOff();
mScrimController.onScreenTurnedOff();
updateIsKeyguard();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 8286d26..24f0b27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -58,7 +58,6 @@
private boolean mBlockEthernet;
private boolean mActivityEnabled;
private boolean mForceBlockWifi;
-
// Track as little state as possible, and only for padding purposes
private boolean mIsAirplaneMode = false;
private boolean mWifiVisible = false;
@@ -177,8 +176,9 @@
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId, boolean roaming) {
+ int qsType, boolean activityIn, boolean activityOut, int volteIcon,
+ String typeContentDescription, String description, boolean isWide,
+ int subId, boolean roaming) {
MobileIconState state = getState(subId);
if (state == null) {
return;
@@ -195,6 +195,7 @@
state.roaming = roaming;
state.activityIn = activityIn && mActivityEnabled;
state.activityOut = activityOut && mActivityEnabled;
+ state.volteId = volteIcon;
// Always send a copy to maintain value type semantics
mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
@@ -388,6 +389,7 @@
public boolean roaming;
public boolean needsLeadingPadding;
public String typeContentDescription;
+ public int volteId;
private MobileIconState(int subId) {
super();
@@ -408,7 +410,8 @@
typeId == that.typeId &&
roaming == that.roaming &&
needsLeadingPadding == that.needsLeadingPadding &&
- Objects.equals(typeContentDescription, that.typeContentDescription);
+ Objects.equals(typeContentDescription, that.typeContentDescription) &&
+ volteId == that.volteId;
}
@Override
@@ -433,6 +436,7 @@
other.roaming = roaming;
other.needsLeadingPadding = needsLeadingPadding;
other.typeContentDescription = typeContentDescription;
+ other.volteId = volteId;
}
private static List<MobileIconState> copyStates(List<MobileIconState> inStates) {
@@ -448,7 +452,8 @@
@Override public String toString() {
return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
- + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
+ + roaming + ", typeId=" + typeId + ", volteId=" + volteId
+ + ", visible=" + visible + ")";
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index e1bb19a..5e47f95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -125,15 +125,16 @@
@Override
public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
final int statusType, final int qsType,final boolean activityIn,
- final boolean activityOut, final String typeContentDescription,
- final String description, final boolean isWide, final int subId, boolean roaming) {
+ final boolean activityOut, final int volteIcon,
+ final String typeContentDescription, final String description, final boolean isWide,
+ final int subId, boolean roaming) {
post(new Runnable() {
@Override
public void run() {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
- activityIn, activityOut, typeContentDescription, description, isWide,
- subId, roaming);
+ activityIn, activityOut, volteIcon, typeContentDescription,
+ description, isWide, subId, roaming);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FiveGServiceClient.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FiveGServiceClient.java
new file mode 100644
index 0000000..74168cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FiveGServiceClient.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_POOR;
+import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_MODERATE;
+import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GOOD;
+import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.DeadObjectException;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.telephony.CellInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.google.android.collect.Lists;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.Exception;
+import java.util.ArrayList;
+import java.lang.ref.WeakReference;
+
+import org.codeaurora.internal.Client;
+import org.codeaurora.internal.IExtTelephony;
+import org.codeaurora.internal.INetworkCallback;
+import org.codeaurora.internal.NetworkCallbackBase;
+import org.codeaurora.internal.NrConfigType;
+import org.codeaurora.internal.NrIconType;
+import org.codeaurora.internal.ServiceUtil;
+import org.codeaurora.internal.SignalStrength;
+import org.codeaurora.internal.Status;
+import org.codeaurora.internal.Token;
+import org.codeaurora.internal.NetworkCallbackBase;
+
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
+
+public class FiveGServiceClient {
+ private static final String TAG = "FiveGServiceClient";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG)||true;
+ private static final int MESSAGE_REBIND = 1024;
+ private static final int MESSAGE_REINIT = MESSAGE_REBIND+1;
+ private static final int MESSAGE_NOTIFIY_MONITOR_CALLBACK = MESSAGE_REBIND+2;
+ private static final int MAX_RETRY = 4;
+ private static final int DELAY_MILLISECOND = 3000;
+ private static final int DELAY_INCREMENT = 2000;
+
+ /**
+ * These threshold values are copied from CellSignalStrengthNr.
+ */
+ private static final int SIGNAL_GREAT_THRESHOLD = -95;
+ private static final int SIGNAL_GOOD_THRESHOLD = -105;
+ private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+
+ private static FiveGServiceClient sInstance;
+ private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
+ mKeyguardUpdateMonitorCallbacks = Lists.newArrayList();
+ @VisibleForTesting
+ final SparseArray<IFiveGStateListener> mStatesListeners = new SparseArray<>();
+ private final SparseArray<FiveGServiceState> mCurrentServiceStates = new SparseArray<>();
+ private final SparseArray<FiveGServiceState> mLastServiceStates = new SparseArray<>();
+
+ private Context mContext;
+ private boolean mServiceConnected;
+ private IExtTelephony mNetworkService;
+ private String mPackageName;
+ private Client mClient;
+ private int mBindRetryTimes = 0;
+ private int mInitRetryTimes = 0;
+
+ public static class FiveGServiceState{
+ private int mLevel;
+ private int mNrConfigType;
+ private int mNrIconType;
+ private MobileIconGroup mIconGroup;
+
+ public FiveGServiceState(){
+ mLevel = 0;
+ mNrConfigType = NrConfigType.NSA_CONFIGURATION;
+ mNrIconType = NrIconType.INVALID;
+ mIconGroup = TelephonyIcons.UNKNOWN;
+ }
+
+ public boolean isNrIconTypeValid() {
+ return mNrIconType != NrIconType.INVALID && mNrIconType != NrIconType.TYPE_NONE;
+ }
+
+ @VisibleForTesting
+ public MobileIconGroup getIconGroup() {
+ return mIconGroup;
+ }
+
+ @VisibleForTesting
+ public int getSignalLevel() {
+ return mLevel;
+ }
+
+ @VisibleForTesting
+ int getNrConfigType() {
+ return mNrConfigType;
+ }
+
+ @VisibleForTesting
+ int getNrIconType() {
+ return mNrIconType;
+ }
+
+ public void copyFrom(FiveGServiceState state) {
+ this.mLevel = state.mLevel;
+ this.mNrConfigType = state.mNrConfigType;
+ this.mIconGroup = state.mIconGroup;
+ this.mNrIconType = state.mNrIconType;
+ }
+
+ public boolean equals(FiveGServiceState state) {
+ return this.mLevel == state.mLevel
+ && this.mNrConfigType == state.mNrConfigType
+ && this.mIconGroup == state.mIconGroup
+ && this.mNrIconType == state.mNrIconType;
+ }
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("mLevel=").append(mLevel).append(", ").
+ append("mNrConfigType=").append(mNrConfigType).append(", ").
+ append("mNrIconType=").append(mNrIconType).append(", ").
+ append("mIconGroup=").append(mIconGroup);
+
+ return builder.toString();
+ }
+ }
+
+ public FiveGServiceClient(Context context) {
+ mContext = context;
+ mPackageName = mContext.getPackageName();
+ }
+
+ public static FiveGServiceClient getInstance(Context context) {
+ if ( sInstance == null ) {
+ sInstance = new FiveGServiceClient(context);
+ }
+
+ return sInstance;
+ }
+
+ public void registerCallback(KeyguardUpdateMonitorCallback callback) {
+ mKeyguardUpdateMonitorCallbacks.add(
+ new WeakReference<KeyguardUpdateMonitorCallback>(callback));
+ }
+
+ public void registerListener(int phoneId, IFiveGStateListener listener) {
+ Log.d(TAG, "registerListener phoneId=" + phoneId);
+
+ mStatesListeners.put(phoneId, listener);
+ if ( !isServiceConnected() ) {
+ binderService();
+ }else{
+ initFiveGServiceState(phoneId);
+ }
+ }
+
+ public void unregisterListener(int phoneId) {
+ Log.d(TAG, "unregisterListener phoneId=" + phoneId);
+ mStatesListeners.remove(phoneId);
+ mCurrentServiceStates.remove(phoneId);
+ mLastServiceStates.remove(phoneId);
+ }
+
+ private void binderService() {
+ boolean success = ServiceUtil.bindService(mContext, mServiceConnection);
+ Log.d(TAG, " bind service " + success);
+ if ( !success && mBindRetryTimes < MAX_RETRY && !mHandler.hasMessages(MESSAGE_REBIND)) {
+ mHandler.sendEmptyMessageDelayed(MESSAGE_REBIND,
+ DELAY_MILLISECOND + mBindRetryTimes*DELAY_INCREMENT);
+ mBindRetryTimes+=1;
+ }
+ }
+
+ public boolean isServiceConnected() {
+ return mServiceConnected;
+ }
+
+ @VisibleForTesting
+ public FiveGServiceState getCurrentServiceState(int phoneId) {
+ return getServiceState(phoneId, mCurrentServiceStates);
+ }
+
+ private FiveGServiceState getLastServiceState(int phoneId) {
+ return getServiceState(phoneId, mLastServiceStates);
+ }
+
+ private static FiveGServiceState getServiceState(int key,
+ SparseArray<FiveGServiceState> array) {
+ FiveGServiceState state = array.get(key);
+ if ( state == null ) {
+ state = new FiveGServiceState();
+ array.put(key, state);
+ }
+ return state;
+ }
+
+ private void notifyListenersIfNecessary(int phoneId) {
+ FiveGServiceState currentState = getCurrentServiceState(phoneId);
+ FiveGServiceState lastState = getLastServiceState(phoneId);
+ if ( !currentState.equals(lastState) ) {
+
+ if ( DEBUG ) {
+ Log.d(TAG, "phoneId(" + phoneId + ") Change in state from " + lastState + " \n"+
+ "\tto " + currentState);
+
+ }
+
+ lastState.copyFrom(currentState);
+ IFiveGStateListener listener = mStatesListeners.get(phoneId);
+ if (listener != null) {
+ listener.onStateChanged(currentState);
+ }
+
+ mHandler.sendEmptyMessage(MESSAGE_NOTIFIY_MONITOR_CALLBACK);
+
+ }
+ }
+
+ private void initFiveGServiceState() {
+ Log.d(TAG, "initFiveGServiceState size=" + mStatesListeners.size());
+ for( int i=0; i < mStatesListeners.size(); ++i ) {
+ int phoneId = mStatesListeners.keyAt(i);
+ initFiveGServiceState(phoneId);
+ }
+ }
+
+ private void initFiveGServiceState(int phoneId) {
+ Log.d(TAG, "mNetworkService=" + mNetworkService + " mClient=" + mClient);
+ if ( mNetworkService != null && mClient != null) {
+ Log.d(TAG, "query 5G service state for phoneId " + phoneId);
+ try {
+ queryNrSignalStrength(phoneId);
+
+ Token token = mNetworkService.query5gConfigInfo(phoneId, mClient);
+ Log.d(TAG, "query5gConfigInfo result:" + token);
+
+ token = mNetworkService.queryNrIconType(phoneId, mClient);
+ Log.d(TAG, "queryNrIconType result:" + token);
+ }catch(DeadObjectException e) {
+ Log.e(TAG, "initFiveGServiceState: Exception = " + e);
+ Log.d(TAG, "try to re-binder service");
+ mInitRetryTimes = 0;
+ mServiceConnected = false;
+ mNetworkService = null;
+ mClient = null;
+ binderService();
+ }catch (Exception e) {
+ Log.d(TAG, "initFiveGServiceState: Exception = " + e);
+ if ( mInitRetryTimes < MAX_RETRY && !mHandler.hasMessages(MESSAGE_REINIT) ) {
+ mHandler.sendEmptyMessageDelayed(MESSAGE_REINIT,
+ DELAY_MILLISECOND + mInitRetryTimes*DELAY_INCREMENT);
+ mInitRetryTimes +=1;
+ }
+ }
+ }
+ }
+
+ public void queryNrSignalStrength(int phoneId) {
+ if ( mNetworkService != null && mClient != null) {
+ Log.d(TAG, "query queryNrSignalStrength for phoneId " + phoneId);
+ try {
+ Token token = mNetworkService.queryNrSignalStrength(phoneId, mClient);
+ Log.d(TAG, "queryNrSignalStrength result:" + token);
+ }catch (Exception e) {
+ Log.e(TAG, "queryNrSignalStrength", e);
+ }
+ }else {
+ Log.e(TAG, "query queryNrSignalStrength for phoneId " + phoneId);
+ }
+ }
+
+ @VisibleForTesting
+ void update5GIcon(FiveGServiceState state,int phoneId) {
+ state.mIconGroup = getNrIconGroup(state.mNrIconType, phoneId);
+ }
+
+ private void updateLevel(int ssRsrp, FiveGServiceState state) {
+ if (ssRsrp == CellInfo.UNAVAILABLE) {
+ state.mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ } else if (ssRsrp >= SIGNAL_GREAT_THRESHOLD) {
+ state.mLevel = SIGNAL_STRENGTH_GREAT;
+ } else if (ssRsrp >= SIGNAL_GOOD_THRESHOLD) {
+ state.mLevel = SIGNAL_STRENGTH_GOOD;
+ } else if (ssRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+ state.mLevel = SIGNAL_STRENGTH_MODERATE;
+ } else {
+ state.mLevel = SIGNAL_STRENGTH_POOR;
+ }
+ }
+
+ private MobileIconGroup getNrIconGroup(int nrIconType , int phoneId) {
+ MobileIconGroup iconGroup = TelephonyIcons.UNKNOWN;
+ switch (nrIconType){
+ case NrIconType.TYPE_5G_BASIC:
+ iconGroup = TelephonyIcons.FIVE_G_BASIC;
+ break;
+ case NrIconType.TYPE_5G_UWB:
+ iconGroup = TelephonyIcons.FIVE_G_UWB;
+ break;
+ }
+ return iconGroup;
+ }
+
+ private void notifyMonitorCallback() {
+ for (int i = 0; i < mKeyguardUpdateMonitorCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mKeyguardUpdateMonitorCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onRefreshCarrierInfo();
+ }
+ }
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ int what = msg.what;
+ switch ( msg.what ) {
+ case MESSAGE_REBIND:
+ binderService();
+ break;
+
+ case MESSAGE_REINIT:
+ initFiveGServiceState();
+ break;
+
+ case MESSAGE_NOTIFIY_MONITOR_CALLBACK:
+ notifyMonitorCallback();
+ break;
+ }
+
+ }
+ };
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "onServiceConnected:" + service);
+
+ try {
+ mNetworkService = IExtTelephony.Stub.asInterface(service);
+ mClient = mNetworkService.registerCallback(mPackageName, mCallback);
+ mServiceConnected = true;
+ initFiveGServiceState();
+ Log.d(TAG, "Client = " + mClient);
+ } catch (Exception e) {
+ Log.d(TAG, "onServiceConnected: Exception = " + e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(TAG, "onServiceDisconnected:" + name);
+ cleanup();
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ Log.d(TAG, "onBindingDied:" + name);
+ cleanup();
+ if ( mBindRetryTimes < MAX_RETRY ) {
+ Log.d(TAG, "try to re-bind");
+ mHandler.sendEmptyMessageDelayed(MESSAGE_REBIND,
+ DELAY_MILLISECOND+mBindRetryTimes*DELAY_INCREMENT);
+ }
+ }
+
+ private void cleanup() {
+ Log.d(TAG, "cleanup");
+ mServiceConnected = false;
+ mNetworkService = null;
+ mClient = null;
+ }
+ };
+
+
+ @VisibleForTesting
+ protected INetworkCallback mCallback = new NetworkCallbackBase() {
+ @Override
+ public void onSignalStrength(int slotId, Token token, Status status,
+ org.codeaurora.internal.SignalStrength
+ signalStrength) throws RemoteException {
+ if ( DEBUG ) {
+ Log.d(TAG, "onSignalStrength: slotId=" + slotId + " token=" + token
+ + " status=" + status + " signalStrength=" + signalStrength);
+ }
+
+ if (status.get() == Status.SUCCESS && signalStrength != null) {
+ FiveGServiceState state = getCurrentServiceState(slotId);
+ updateLevel(signalStrength.getRsrp(), state);
+ notifyListenersIfNecessary(slotId);
+ }
+ }
+
+ @Override
+ public void on5gConfigInfo(int slotId, Token token, Status status, NrConfigType
+ nrConfigType) throws RemoteException {
+ Log.d(TAG,
+ "on5gConfigInfo: slotId = " + slotId + " token = " + token + " " + "status"
+ + status + " NrConfigType = " + nrConfigType);
+ if (status.get() == Status.SUCCESS) {
+ FiveGServiceState state = getCurrentServiceState(slotId);
+ state.mNrConfigType = nrConfigType.get();
+ notifyListenersIfNecessary(slotId);
+ }
+ }
+
+ @Override
+ public void onNrIconType(int slotId, Token token, Status status, NrIconType
+ nrIconType) throws RemoteException {
+ Log.d(TAG,
+ "onNrIconType: slotId = " + slotId + " token = " + token + " " + "status"
+ + status + " NrIconType = " + nrIconType);
+ if (status.get() == Status.SUCCESS) {
+ FiveGServiceState state = getCurrentServiceState(slotId);
+ state.mNrIconType = nrIconType.get();
+ update5GIcon(state, slotId);
+ notifyListenersIfNecessary(slotId);
+ }
+ }
+ };
+
+ public interface IFiveGStateListener {
+ public void onStateChanged(FiveGServiceState state);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 8f201c7..e8bc7db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -233,6 +233,17 @@
@Override
public void onNumClientsChanged(int numConnectedDevices) {
+ // Do nothing - we don't care about changing anything here.
+ }
+
+ @Override
+ public void onStaConnected(String Macaddr, int numConnectedDevices) {
+ mNumConnectedDevices = numConnectedDevices;
+ fireHotspotChangedCallback();
+ }
+
+ @Override
+ public void onStaDisconnected(String Macaddr, int numConnectedDevices) {
mNumConnectedDevices = numConnectedDevices;
fireHotspotChangedCallback();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 5da7267..8883bb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -15,14 +15,21 @@
*/
package com.android.systemui.statusbar.policy;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings.Global;
+import android.telephony.CellSignalStrengthNr;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.feature.MmTelFeature;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -34,13 +41,20 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.PhoneConstants.DataState;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.FiveGServiceClient;
+import com.android.systemui.statusbar.policy.FiveGServiceClient.FiveGServiceState;
+import com.android.systemui.statusbar.policy.FiveGServiceClient.IFiveGStateListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
@@ -48,6 +62,7 @@
import java.io.PrintWriter;
import java.util.BitSet;
+import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -77,6 +92,7 @@
// of code.
private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+ private DataState mMMSDataState = DataState.DISCONNECTED;
private ServiceState mServiceState;
private SignalStrength mSignalStrength;
private MobileIconGroup mDefaultIcons;
@@ -89,6 +105,20 @@
// Some specific carriers have 5GE network which is special LTE CA network.
private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
+ private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+
+ /****************************SideCar****************************/
+ @VisibleForTesting
+ FiveGStateListener mFiveGStateListener;
+ @VisibleForTesting
+ FiveGServiceState mFiveGState;
+ private FiveGServiceClient mClient;
+ private CellSignalStrengthNr mCellSignalStrengthNr;
+ /**********************************************************/
+
+ private ImsManager mImsManager;
+ private ImsManager.Connector mImsManagerConnector;
+
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(Context context, Config config, boolean hasMobileData,
@@ -103,6 +133,8 @@
mPhone = phone;
mDefaults = defaults;
mSubscriptionInfo = info;
+ mFiveGStateListener = new FiveGStateListener();
+ mFiveGState = new FiveGServiceState();
mPhoneStateListener = new MobilePhoneStateListener(receiverLooper);
mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
mNetworkNameDefault = getStringIfExists(
@@ -118,6 +150,25 @@
mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
// Get initial data sim state.
updateDataSim();
+
+ int phoneId = mSubscriptionInfo.getSimSlotIndex();
+ mImsManagerConnector = new ImsManager.Connector(mContext, phoneId,
+ new ImsManager.Connector.Listener() {
+ @Override
+ public void connectionReady(ImsManager manager) throws ImsException {
+ Log.d(mTag, "ImsManager: connection ready.");
+ mImsManager = manager;
+ setListeners();
+ }
+
+ @Override
+ public void connectionUnavailable() {
+ Log.d(mTag, "ImsManager: connection unavailable.");
+ removeListeners();
+ }
+ });
+
+
mObserver = new ContentObserver(new Handler(receiverLooper)) {
@Override
public void onChange(boolean selfChange) {
@@ -188,6 +239,9 @@
mContext.getContentResolver().registerContentObserver(Global.getUriFor(
Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
true, mObserver);
+ mContext.registerReceiver(mVolteSwitchObserver,
+ new IntentFilter("org.codeaurora.intent.action.ACTION_ENHANCE_4G_SWITCH"));
+ mImsManagerConnector.connect();
}
/**
@@ -196,6 +250,8 @@
public void unregisterListener() {
mPhone.listen(mPhoneStateListener, 0);
mContext.getContentResolver().unregisterContentObserver(mObserver);
+ mContext.unregisterReceiver(mVolteSwitchObserver);
+ mImsManagerConnector.disconnect();
}
/**
@@ -211,6 +267,7 @@
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_NR, TelephonyIcons.FIVE_G_SA);
if (!mConfig.showAtLeast3G) {
mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -292,12 +349,16 @@
if (mInflateSignalStrengths) {
level++;
}
+
boolean dataDisabled = mCurrentState.userSetup
&& (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
|| (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA
&& mCurrentState.defaultDataOff));
boolean noInternet = mCurrentState.inetCondition == 0;
boolean cutOut = dataDisabled || noInternet;
+ if (mConfig.hideNoInternetState) {
+ cutOut = false;
+ }
return SignalDrawable.getState(level, getNumLevels(), cutOut);
} else if (mCurrentState.enabled) {
return SignalDrawable.getEmptyState(getNumLevels());
@@ -311,6 +372,75 @@
return getCurrentIconId();
}
+ private boolean isVolteSwitchOn() {
+ return mImsManager != null && mImsManager.isEnhanced4gLteModeSettingEnabledByUser();
+ }
+
+ private int getVolteResId() {
+ int resId = 0;
+ int voiceNetTye = getVoiceNetworkType();
+ if ( (mCurrentState.voiceCapable || mCurrentState.videoCapable)
+ && mCurrentState.imsRegistered ) {
+ resId = R.drawable.ic_volte;
+ }else if ( mDataNetType == TelephonyManager.NETWORK_TYPE_LTE
+ || mDataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA
+ || voiceNetTye == TelephonyManager.NETWORK_TYPE_LTE
+ || voiceNetTye == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ resId = R.drawable.ic_volte_no_voice;
+ }
+ return resId;
+ }
+
+ private void setListeners() {
+ if (mImsManager == null) {
+ Log.e(mTag, "setListeners mImsManager is null");
+ return;
+ }
+
+ try {
+ mImsManager.addCapabilitiesCallback(mCapabilityCallback);
+ mImsManager.addRegistrationCallback(mImsRegistrationCallback);
+ Log.d(mTag, "addCapabilitiesCallback " + mCapabilityCallback + " into " + mImsManager);
+ Log.d(mTag, "addRegistrationCallback " + mImsRegistrationCallback
+ + " into " + mImsManager);
+ } catch (ImsException e) {
+ Log.d(mTag, "unable to addCapabilitiesCallback callback.");
+ }
+ queryImsState();
+ }
+
+ private void queryImsState() {
+ TelephonyManager tm = mPhone.createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
+ mCurrentState.voiceCapable = tm.isVolteAvailable();
+ mCurrentState.videoCapable = tm.isVideoTelephonyAvailable();
+ mCurrentState.imsRegistered = mPhone.isImsRegistered(mSubscriptionInfo.getSubscriptionId());
+ if (DEBUG) {
+ Log.d(mTag, "queryImsState tm=" + tm + " phone=" + mPhone
+ + " voiceCapable=" + mCurrentState.voiceCapable
+ + " videoCapable=" + mCurrentState.videoCapable
+ + " imsResitered=" + mCurrentState.imsRegistered);
+ }
+ notifyListenersIfNecessary();
+ }
+
+ private void removeListeners() {
+ if (mImsManager == null) {
+ Log.e(mTag, "removeListeners mImsManager is null");
+ return;
+ }
+
+ try {
+ mImsManager.removeCapabilitiesCallback(mCapabilityCallback);
+ mImsManager.removeRegistrationListener(mImsRegistrationCallback);
+ Log.d(mTag, "removeCapabilitiesCallback " + mCapabilityCallback
+ + " from " + mImsManager);
+ Log.d(mTag, "removeRegistrationCallback " + mImsRegistrationCallback
+ + " from " + mImsManager);
+ } catch (ImsException e) {
+ Log.d(mTag, "unable to remove callback.");
+ }
+ }
+
@Override
public void notifyListeners(SignalCallback callback) {
MobileIconGroup icons = getIcons();
@@ -346,9 +476,25 @@
&& !mCurrentState.carrierNetworkChangeMode
&& mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
- int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.mDataType : 0;
+ int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon
+ || mConfig.alwaysShowNetworkTypeIcon) ? icons.mDataType : 0;
+ int volteIcon = mConfig.showVolteIcon && isVolteSwitchOn() ? getVolteResId() : 0;
+ if (DEBUG) {
+ Log.d(mTag, "notifyListeners mConfig.alwaysShowNetworkTypeIcon="
+ + mConfig.alwaysShowNetworkTypeIcon + " mDataNetType:" + mDataNetType +
+ "/" + TelephonyManager.getNetworkTypeName(mDataNetType)
+ + " voiceNetType=" + getVoiceNetworkType() + "/"
+ + TelephonyManager.getNetworkTypeName(getVoiceNetworkType())
+ + " showDataIcon=" + showDataIcon
+ + " mConfig.alwaysShowDataRatIcon=" + mConfig.alwaysShowDataRatIcon
+ + " icons.mDataType=" + icons.mDataType
+ + " mConfig.showVolteIcon=" + mConfig.showVolteIcon
+ + " isVolteSwitchOn=" + isVolteSwitchOn()
+ + " volteIcon=" + volteIcon);
+ }
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
- activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
+ activityIn, activityOut,volteIcon,
+ dataContentDescription, description, icons.mIsWide,
mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
}
@@ -396,6 +542,16 @@
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
updateDataSim();
notifyListenersIfNecessary();
+ }else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+ String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
+ String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
+ if ("mms".equals(apnType)) {
+ if (DEBUG) {
+ Log.d(mTag, "handleBroadcast MMS connection state=" + state);
+ }
+ mMMSDataState = DataState.valueOf(state);
+ updateTelephony();
+ }
}
}
@@ -493,6 +649,27 @@
mCurrentState.level = mSignalStrength.getCdmaLevel();
} else {
mCurrentState.level = mSignalStrength.getLevel();
+ if (mConfig.showRsrpSignalLevelforLTE) {
+ if (DEBUG) {
+ Log.d(mTag, "updateTelephony CS:" + mServiceState.getVoiceNetworkType()
+ + "/" + TelephonyManager.getNetworkTypeName(
+ mServiceState.getVoiceNetworkType())
+ + ", PS:" + mServiceState.getDataNetworkType()
+ + "/"+ TelephonyManager.getNetworkTypeName(
+ mServiceState.getDataNetworkType()));
+ }
+ int dataType = mServiceState.getDataNetworkType();
+ if (dataType == TelephonyManager.NETWORK_TYPE_LTE ||
+ dataType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ mCurrentState.level = getAlternateLteLevel(mSignalStrength);
+ }else if ( dataType == TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+ int voiceType = mServiceState.getVoiceNetworkType();
+ if (voiceType == TelephonyManager.NETWORK_TYPE_LTE ||
+ voiceType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ mCurrentState.level = getAlternateLteLevel(mSignalStrength);
+ }
+ }
+ }
}
}
@@ -510,8 +687,37 @@
} else {
mCurrentState.iconGroup = mDefaultIcons;
}
+
+ if ( mDataNetType == TelephonyManager.NETWORK_TYPE_NR ) {
+ if (mFiveGState.isNrIconTypeValid()) {
+ mCurrentState.iconGroup = mFiveGState.getIconGroup();
+ if (DEBUG) {
+ Log.d(mTag,"get 5G SA icon from side-car");
+ }
+ }
+ int nrLevel = getNrLevel();
+ if (nrLevel > mFiveGState.getSignalLevel()) {
+ mCurrentState.level = nrLevel;
+ if (DEBUG) {
+ Log.d(mTag,"get 5G SA sinal strength from AOSP");
+ }
+ }else{
+ mCurrentState.level = mFiveGState.getSignalLevel();
+ if (DEBUG) {
+ Log.d(mTag,"get 5G SA sinal strength from side-car");
+ }
+ }
+
+ }else if ( nr5GIconGroup == null && isSideCarNsaValid() ) {
+ mCurrentState.iconGroup = mFiveGState.getIconGroup();
+ if (DEBUG) {
+ Log.d(mTag,"get 5G NSA icon from side-car");
+ }
+ }
+
mCurrentState.dataConnected = mCurrentState.connected
- && mDataState == TelephonyManager.DATA_CONNECTED;
+ && (mDataState == TelephonyManager.DATA_CONNECTED
+ || mMMSDataState == DataState.CONNECTED);
mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
@@ -540,6 +746,23 @@
mCurrentState.networkNameData = mServiceState.getDataOperatorAlphaShort();
}
+
+ if ( mConfig.alwaysShowNetworkTypeIcon && nr5GIconGroup == null) {
+ int iconType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ if ( mCurrentState.connected ) {
+ if (isDataNetworkTypeAvailable()) {
+ iconType = mDataNetType;
+ } else {
+ iconType = getVoiceNetworkType();
+ }
+ }
+ if (mNetworkToIconLookup.indexOfKey(iconType) >= 0) {
+ mCurrentState.iconGroup = mNetworkToIconLookup.get(iconType);
+ } else {
+ mCurrentState.iconGroup = mDefaultIcons;
+ }
+ }
+
notifyListenersIfNecessary();
}
@@ -640,6 +863,67 @@
return !mPhone.isDataCapable();
}
+ private boolean isDataNetworkTypeAvailable() {
+ boolean isAvailable = true;
+ if ( mDataNetType == TelephonyManager.NETWORK_TYPE_UNKNOWN ) {
+ isAvailable = false;
+ }else {
+ int dataType = getDataNetworkType();
+ int voiceType = getVoiceNetworkType();
+ if ((dataType == TelephonyManager.NETWORK_TYPE_EVDO_A
+ || dataType == TelephonyManager.NETWORK_TYPE_EVDO_B
+ || dataType == TelephonyManager.NETWORK_TYPE_EHRPD
+ || dataType == TelephonyManager.NETWORK_TYPE_LTE
+ || dataType == TelephonyManager.NETWORK_TYPE_LTE_CA)
+ && (voiceType == TelephonyManager.NETWORK_TYPE_GSM
+ || voiceType == TelephonyManager.NETWORK_TYPE_1xRTT
+ || voiceType == TelephonyManager.NETWORK_TYPE_CDMA)
+ && ( !isCallIdle() )) {
+ isAvailable = false;
+ }
+ }
+
+ return isAvailable;
+ }
+
+ private boolean isCallIdle() {
+ return mCallState == TelephonyManager.CALL_STATE_IDLE;
+ }
+
+ private int getVoiceNetworkType() {
+ return mServiceState != null ?
+ mServiceState.getVoiceNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ }
+
+ private int getDataNetworkType() {
+ return mServiceState != null ?
+ mServiceState.getDataNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ }
+
+ private int getAlternateLteLevel(SignalStrength signalStrength) {
+ int lteRsrp = signalStrength.getLteDbm();
+ if ( lteRsrp == SignalStrength.INVALID ) {
+ int signalStrengthLevel = signalStrength.getLevel();
+ if (DEBUG) {
+ Log.d(mTag, "getAlternateLteLevel lteRsrp:INVALID "
+ + " signalStrengthLevel = " + signalStrengthLevel);
+ }
+ return signalStrengthLevel;
+ }
+
+ int rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ if (lteRsrp > -44) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ else if (lteRsrp >= -97) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ else if (lteRsrp >= -105) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_GOOD;
+ else if (lteRsrp >= -113) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_MODERATE;
+ else if (lteRsrp >= -120) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_POOR;
+ else if (lteRsrp >= -140) rsrpLevel = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ if (DEBUG) {
+ Log.d(mTag, "getAlternateLteLevel lteRsrp:" + lteRsrp + " rsrpLevel = " + rsrpLevel);
+ }
+ return rsrpLevel;
+ }
+
@VisibleForTesting
void setActivity(int activity) {
mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
@@ -651,6 +935,39 @@
notifyListenersIfNecessary();
}
+ public void registerFiveGStateListener(FiveGServiceClient client) {
+ int phoneId = mSubscriptionInfo.getSimSlotIndex();
+ client.registerListener(phoneId, mFiveGStateListener);
+ mClient = client;
+ }
+
+ public void unregisterFiveGStateListener(FiveGServiceClient client) {
+ int phoneId = mSubscriptionInfo.getSimSlotIndex();
+ client.unregisterListener(phoneId);
+ }
+
+ private boolean isDataRegisteredOnLte() {
+ boolean registered = false;
+ int dataType = getDataNetworkType();
+ if (dataType == TelephonyManager.NETWORK_TYPE_LTE ||
+ dataType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ registered = true;
+ }
+ return registered;
+ }
+
+ private boolean isSideCarNsaValid() {
+ return mFiveGState.isNrIconTypeValid() && isDataRegisteredOnLte();
+ }
+
+ private boolean isCellSignalStrengthNrValid() {
+ return ( mCellSignalStrengthNr != null && mCellSignalStrengthNr.isValid());
+ }
+
+ private int getNrLevel() {
+ return mCellSignalStrengthNr != null ? mCellSignalStrengthNr.getLevel() : 0;
+ }
+
@Override
public void dump(PrintWriter pw) {
super.dump(pw);
@@ -662,6 +979,7 @@
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
+ pw.println(" mFiveGState=" + mFiveGState + ",");
}
class MobilePhoneStateListener extends PhoneStateListener {
@@ -676,9 +994,30 @@
((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
}
mSignalStrength = signalStrength;
+ updateCellSignalStrengthNr(signalStrength);
updateTelephony();
}
+ private void updateCellSignalStrengthNr(SignalStrength signalStrength) {
+ if ( signalStrength != null ) {
+ List<CellSignalStrengthNr> ssNrList =
+ mSignalStrength.getCellSignalStrengths(CellSignalStrengthNr.class);
+ if (ssNrList != null && ssNrList.size() > 0) {
+ mCellSignalStrengthNr = ssNrList.get(0);
+ }else {
+ mCellSignalStrengthNr = null;
+ }
+ }else {
+ mCellSignalStrengthNr = null;
+ }
+
+ if ( mDataNetType == TelephonyManager.NETWORK_TYPE_NR
+ && !isCellSignalStrengthNrValid()
+ && mClient != null){
+ mClient.queryNrSignalStrength(mSubscriptionInfo.getSimSlotIndex());
+ }
+ }
+
@Override
public void onServiceStateChanged(ServiceState state) {
if (DEBUG) {
@@ -738,6 +1077,73 @@
updateDataSim();
updateTelephony();
}
+
+ @Override
+ public void onCallStateChanged(int state, String phoneNumber) {
+ if (DEBUG) {
+ Log.d(mTag, "onCallStateChanged: state=" + state);
+ }
+ mCallState = state;
+ updateTelephony();
+ }
+ };
+
+ class FiveGStateListener implements IFiveGStateListener{
+
+ public void onStateChanged(FiveGServiceState state) {
+ if (DEBUG) {
+ Log.d(mTag, "onStateChanged: state=" + state);
+ }
+ mFiveGState = state;
+ updateTelephony();
+ notifyListeners();
+ }
+ }
+
+ private ImsMmTelManager.CapabilityCallback mCapabilityCallback = new ImsMmTelManager.CapabilityCallback() {
+ @Override
+ public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities config) {
+ mCurrentState.voiceCapable =
+ config.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
+ mCurrentState.videoCapable =
+ config.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
+ Log.d(mTag, "onCapabilitiesStatusChanged isVoiceCapable=" + mCurrentState.voiceCapable
+ + " isVideoCapable=" + mCurrentState.videoCapable);
+ notifyListenersIfNecessary();
+ }
+ };
+
+ private final ImsMmTelManager.RegistrationCallback mImsRegistrationCallback =
+ new ImsMmTelManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(int imsTransportType) {
+ Log.d(mTag, "onRegistered imsTransportType=" + imsTransportType);
+ mCurrentState.imsRegistered = true;
+ notifyListenersIfNecessary();
+ }
+
+ @Override
+ public void onRegistering(int imsTransportType) {
+ Log.d(mTag, "onRegistering imsTransportType=" + imsTransportType);
+ mCurrentState.imsRegistered = false;
+ notifyListenersIfNecessary();
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ Log.d(mTag, "onDeregistered imsReasonInfo=" + info);
+ mCurrentState.imsRegistered = false;
+ notifyListenersIfNecessary();
+ }
+ };
+
+ private final BroadcastReceiver mVolteSwitchObserver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ Log.d(mTag, "action=" + intent.getAction());
+ if ( mConfig.showVolteIcon ) {
+ notifyListeners();
+ }
+ }
};
static class MobileIconGroup extends SignalController.IconGroup {
@@ -770,6 +1176,10 @@
boolean userSetup;
boolean roaming;
boolean defaultDataOff; // Tracks the on/off state of the defaultDataSubscription
+ boolean imsRegistered;
+ boolean voiceCapable;
+ boolean videoCapable;
+
@Override
public void copyFrom(State s) {
@@ -786,6 +1196,9 @@
userSetup = state.userSetup;
roaming = state.roaming;
defaultDataOff = state.defaultDataOff;
+ imsRegistered = state.imsRegistered;
+ voiceCapable = state.voiceCapable;
+ videoCapable = state.videoCapable;
}
@Override
@@ -804,6 +1217,9 @@
.append(',');
builder.append("userSetup=").append(userSetup).append(',');
builder.append("defaultDataOff=").append(defaultDataOff);
+ builder.append("imsRegistered=").append(imsRegistered).append(',');
+ builder.append("voiceCapable=").append(voiceCapable).append(',');
+ builder.append("videoCapable=").append(videoCapable);
}
@Override
@@ -819,7 +1235,10 @@
&& ((MobileState) o).userSetup == userSetup
&& ((MobileState) o).isDefault == isDefault
&& ((MobileState) o).roaming == roaming
- && ((MobileState) o).defaultDataOff == defaultDataOff;
+ && ((MobileState) o).defaultDataOff == defaultDataOff
+ && ((MobileState) o).imsRegistered == imsRegistered
+ && ((MobileState) o).voiceCapable == voiceCapable
+ && ((MobileState) o).videoCapable == videoCapable;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 71db618..e24aa13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -52,8 +52,9 @@
String statusLabel) {}
default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
- String description, boolean isWide, int subId, boolean roaming) {}
+ int qsType, boolean activityIn, boolean activityOut, int volteIcon,
+ String typeContentDescription, String description, boolean isWide,
+ int subId, boolean roaming) {}
default void setSubs(List<SubscriptionInfo> subs) {}
default void setNoSims(boolean show, boolean simDetected) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 60784c9..e36d283 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -165,6 +165,8 @@
private boolean mUserSetup;
private boolean mSimDetected;
+ @VisibleForTesting
+ FiveGServiceClient mFiveGServiceClient;
/**
* Construct this controller object and register for updates.
*/
@@ -243,7 +245,7 @@
deviceProvisionedController.getCurrentUser()));
}
});
-
+ mFiveGServiceClient = FiveGServiceClient.getInstance(context);
ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback(){
private Network mLastNetwork;
private NetworkCapabilities mLastNetworkCapabilities;
@@ -293,6 +295,7 @@
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.registerListener();
+ mobileSignalController.registerFiveGStateListener(mFiveGServiceClient);
}
if (mSubscriptionListener == null) {
mSubscriptionListener = new SubListener();
@@ -315,6 +318,7 @@
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
@@ -326,6 +330,7 @@
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.unregisterListener();
+ mobileSignalController.unregisterFiveGStateListener(mFiveGServiceClient);
}
mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
mContext.unregisterReceiver(this);
@@ -693,6 +698,7 @@
}
if (mListening) {
controller.registerListener();
+ controller.registerFiveGStateListener(mFiveGServiceClient);
}
}
}
@@ -703,6 +709,7 @@
mDefaultSignalController = null;
}
cachedControllers.get(key).unregisterListener();
+ cachedControllers.get(key).unregisterFiveGStateListener(mFiveGServiceClient);
}
}
mCallbackHandler.setSubs(subscriptions);
@@ -1155,6 +1162,10 @@
public String patternOfCarrierSpecificDataIcon = "";
public long nrIconDisplayGracePeriodMs;
+ boolean showRsrpSignalLevelforLTE = false;
+ boolean hideNoInternetState = false;
+ boolean showVolteIcon = false;
+ boolean alwaysShowNetworkTypeIcon = false;
/**
* Mapping from NR 5G status string to an integer. The NR 5G status string should match
* those in carrier config.
@@ -1181,6 +1192,13 @@
config.inflateSignalStrengths = res.getBoolean(
com.android.internal.R.bool.config_inflateSignalStrength);
+ config.alwaysShowNetworkTypeIcon =
+ context.getResources().getBoolean(R.bool.config_alwaysShowTypeIcon);
+ config.showRsrpSignalLevelforLTE =
+ res.getBoolean(R.bool.config_showRsrpSignalLevelforLTE);
+ config.hideNoInternetState = res.getBoolean(R.bool.config_hideNoInternetState);
+ config.showVolteIcon = res.getBoolean(R.bool.config_display_volte);
+
CarrierConfigManager configMgr = (CarrierConfigManager)
context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
// Handle specific carrier config values for the default data SIM
@@ -1210,7 +1228,6 @@
b.getInt(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT),
config);
}
-
return config;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index c22ff8b..fc5c405 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -39,6 +39,9 @@
static final int ICON_1X = R.drawable.ic_1x_mobiledata;
static final int ICON_5G = R.drawable.ic_5g_mobiledata;
static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
+ static final int ICON_5G_SA = R.drawable.ic_5g_mobiledata;
+ static final int ICON_5G_BASIC = R.drawable.ic_5g_mobiledata;
+ static final int ICON_5G_UWB = R.drawable.ic_5g_uwb_mobiledata;
static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
"CARRIER_NETWORK_CHANGE",
@@ -274,6 +277,58 @@
// When adding a new MobileIconGround, check if the dataContentDescription has to be filtered
// in QSCarrier#hasValidTypeContentDescription
+ //
+ static final MobileIconGroup FIVE_G = new MobileIconGroup(
+ "5G",
+ null,
+ null,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ 0,
+ 0,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.data_connection_5g,
+ TelephonyIcons.ICON_5G,
+ false);
+
+ static final MobileIconGroup FIVE_G_BASIC = new MobileIconGroup(
+ "5GBasic",
+ null,
+ null,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ 0,
+ 0,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.data_connection_5g_basic,
+ TelephonyIcons.ICON_5G_BASIC,
+ false);
+
+ static final MobileIconGroup FIVE_G_UWB = new MobileIconGroup(
+ "5GUWB",
+ null,
+ null,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ 0,
+ 0,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.data_connection_5g_uwb,
+ TelephonyIcons.ICON_5G_UWB,
+ false);
+
+ static final MobileIconGroup FIVE_G_SA = new MobileIconGroup(
+ "5GSA",
+ null,
+ null,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+ 0, 0,
+ 0,
+ 0,
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+ R.string.data_connection_5g_sa,
+ TelephonyIcons.ICON_5G_SA,
+ false);
/** Mapping icon name(lower case) to the icon object. */
static final Map<String, MobileIconGroup> ICON_NAME_TO_ICON;
@@ -295,6 +350,7 @@
ICON_NAME_TO_ICON.put("lte+", LTE_PLUS);
ICON_NAME_TO_ICON.put("5g", NR_5G);
ICON_NAME_TO_ICON.put("5g_plus", NR_5G_PLUS);
+ ICON_NAME_TO_ICON.put("5guwb", FIVE_G_UWB);
ICON_NAME_TO_ICON.put("datadisable", DATA_DISABLED);
ICON_NAME_TO_ICON.put("notdefaultdata", NOT_DEFAULT_DATA);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index 9db109d..4fe1d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -36,12 +36,82 @@
R.drawable.ic_qs_wifi_4
};
+ static final int[] WIFI_4_FULL_ICONS = {
+ com.android.internal.R.drawable.ic_wifi_4_signal_0,
+ com.android.internal.R.drawable.ic_wifi_4_signal_1,
+ com.android.internal.R.drawable.ic_wifi_4_signal_2,
+ com.android.internal.R.drawable.ic_wifi_4_signal_3,
+ com.android.internal.R.drawable.ic_wifi_4_signal_4
+ };
+
+ private static final int[] WIFI_4_NO_INTERNET_ICONS = {
+ R.drawable.ic_qs_wifi_4_0,
+ R.drawable.ic_qs_wifi_4_1,
+ R.drawable.ic_qs_wifi_4_2,
+ R.drawable.ic_qs_wifi_4_3,
+ R.drawable.ic_qs_wifi_4_4
+ };
+
+ static final int[] WIFI_5_FULL_ICONS = {
+ com.android.internal.R.drawable.ic_wifi_5_signal_0,
+ com.android.internal.R.drawable.ic_wifi_5_signal_1,
+ com.android.internal.R.drawable.ic_wifi_5_signal_2,
+ com.android.internal.R.drawable.ic_wifi_5_signal_3,
+ com.android.internal.R.drawable.ic_wifi_5_signal_4
+ };
+
+ private static final int[] WIFI_5_NO_INTERNET_ICONS = {
+ R.drawable.ic_qs_wifi_5_0,
+ R.drawable.ic_qs_wifi_5_1,
+ R.drawable.ic_qs_wifi_5_2,
+ R.drawable.ic_qs_wifi_5_3,
+ R.drawable.ic_qs_wifi_5_4
+ };
+
+ static final int[] WIFI_6_FULL_ICONS = {
+ com.android.internal.R.drawable.ic_wifi_6_signal_0,
+ com.android.internal.R.drawable.ic_wifi_6_signal_1,
+ com.android.internal.R.drawable.ic_wifi_6_signal_2,
+ com.android.internal.R.drawable.ic_wifi_6_signal_3,
+ com.android.internal.R.drawable.ic_wifi_6_signal_4
+ };
+
+ private static final int[] WIFI_6_NO_INTERNET_ICONS = {
+ R.drawable.ic_qs_wifi_6_0,
+ R.drawable.ic_qs_wifi_6_1,
+ R.drawable.ic_qs_wifi_6_2,
+ R.drawable.ic_qs_wifi_6_3,
+ R.drawable.ic_qs_wifi_6_4
+ };
+
public static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
WIFI_NO_INTERNET_ICONS,
WIFI_FULL_ICONS
};
+
static final int[][] WIFI_SIGNAL_STRENGTH = QS_WIFI_SIGNAL_STRENGTH;
+ public static final int[][] QS_WIFI_4_SIGNAL_STRENGTH = {
+ WIFI_4_NO_INTERNET_ICONS,
+ WIFI_4_FULL_ICONS
+ };
+
+ static final int[][] WIFI_4_SIGNAL_STRENGTH = QS_WIFI_4_SIGNAL_STRENGTH;
+
+ public static final int[][] QS_WIFI_5_SIGNAL_STRENGTH = {
+ WIFI_5_NO_INTERNET_ICONS,
+ WIFI_5_FULL_ICONS
+ };
+
+ static final int[][] WIFI_5_SIGNAL_STRENGTH = QS_WIFI_5_SIGNAL_STRENGTH;
+
+ public static final int[][] QS_WIFI_6_SIGNAL_STRENGTH = {
+ WIFI_6_NO_INTERNET_ICONS,
+ WIFI_6_FULL_ICONS
+ };
+
+ static final int[][] WIFI_6_SIGNAL_STRENGTH = QS_WIFI_6_SIGNAL_STRENGTH;
+
public static final int QS_WIFI_DISABLED = com.android.internal.R.drawable.ic_wifi_signal_0;
public static final int QS_WIFI_NO_NETWORK = com.android.internal.R.drawable.ic_wifi_signal_0;
static final int WIFI_NO_NETWORK = QS_WIFI_NO_NETWORK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
old mode 100644
new mode 100755
index a441f66..1029fd0
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -40,6 +40,10 @@
private final boolean mHasMobileData;
private final WifiManager mWifiManager;
private final WifiStatusTracker mWifiTracker;
+ private final IconGroup mDefaultWifiIconGroup;
+ private final IconGroup mWifi4IconGroup;
+ private final IconGroup mWifi5IconGroup;
+ private final IconGroup mWifi6IconGroup;
public WifiSignalController(Context context, boolean hasMobileData,
CallbackHandler callbackHandler, NetworkControllerImpl networkController,
@@ -55,8 +59,8 @@
connectivityManager, this::handleStatusUpdated);
mWifiTracker.setListening(true);
mHasMobileData = hasMobileData;
- // WiFi only has one state.
- mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
+
+ mDefaultWifiIconGroup = new IconGroup(
"Wi-Fi Icons",
WifiIcons.WIFI_SIGNAL_STRENGTH,
WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
@@ -67,6 +71,44 @@
WifiIcons.QS_WIFI_NO_NETWORK,
AccessibilityContentDescriptions.WIFI_NO_CONNECTION
);
+
+ mWifi4IconGroup = new IconGroup(
+ "Wi-Fi 4 Icons",
+ WifiIcons.WIFI_4_SIGNAL_STRENGTH,
+ WifiIcons.QS_WIFI_4_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+ );
+
+ mWifi5IconGroup = new IconGroup(
+ "Wi-Fi 5 Icons",
+ WifiIcons.WIFI_5_SIGNAL_STRENGTH,
+ WifiIcons.QS_WIFI_5_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+ );
+
+ mWifi6IconGroup = new IconGroup(
+ "Wi-Fi 6 Icons",
+ WifiIcons.WIFI_6_SIGNAL_STRENGTH,
+ WifiIcons.QS_WIFI_6_SIGNAL_STRENGTH,
+ AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ WifiIcons.WIFI_NO_NETWORK,
+ WifiIcons.QS_WIFI_NO_NETWORK,
+ AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+ );
+
+ mCurrentState.iconGroup = mLastState.iconGroup = mDefaultWifiIconGroup;
}
@Override
@@ -81,10 +123,8 @@
@Override
public void notifyListeners(SignalCallback callback) {
// only show wifi in the cluster if connected or if wifi-only
- boolean visibleWhenEnabled = mContext.getResources().getBoolean(
- R.bool.config_showWifiIndicatorWhenEnabled);
boolean wifiVisible = mCurrentState.enabled
- && (mCurrentState.connected || !mHasMobileData || visibleWhenEnabled);
+ && (mCurrentState.connected || !mHasMobileData);
String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getStringIfExists(getContentDescription());
@@ -99,6 +139,19 @@
wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
}
+
+ private void updateIconGroup() {
+ if (mCurrentState.wifiGenerationVersion == 4) {
+ mCurrentState.iconGroup = mWifi4IconGroup;
+ } else if (mCurrentState.wifiGenerationVersion == 5) {
+ mCurrentState.iconGroup = mCurrentState.isReady ? mWifi6IconGroup : mWifi5IconGroup;
+ } else if (mCurrentState.wifiGenerationVersion == 6) {
+ mCurrentState.iconGroup = mWifi6IconGroup;
+ } else {
+ mCurrentState.iconGroup = mDefaultWifiIconGroup;
+ }
+
+ }
/**
* Extract wifi state directly from broadcasts about changes in wifi state.
*/
@@ -110,6 +163,10 @@
mCurrentState.rssi = mWifiTracker.rssi;
mCurrentState.level = mWifiTracker.level;
mCurrentState.statusLabel = mWifiTracker.statusLabel;
+ mCurrentState.wifiGenerationVersion = mWifiTracker.wifiGeneration;
+ mCurrentState.isReady = (mWifiTracker.vhtMax8SpatialStreamsSupport
+ && mWifiTracker.twtSupport);
+ updateIconGroup();
notifyListenersIfNecessary();
}
@@ -145,12 +202,16 @@
String ssid;
boolean isTransient;
String statusLabel;
+ int wifiGenerationVersion;
+ boolean isReady;
@Override
public void copyFrom(State s) {
super.copyFrom(s);
WifiState state = (WifiState) s;
ssid = state.ssid;
+ wifiGenerationVersion = state.wifiGenerationVersion;
+ isReady = state.isReady;
isTransient = state.isTransient;
statusLabel = state.statusLabel;
}
@@ -159,6 +220,8 @@
protected void toString(StringBuilder builder) {
super.toString(builder);
builder.append(",ssid=").append(ssid)
+ .append(",wifiGenerationVersion=").append(wifiGenerationVersion)
+ .append(",isReady=").append(isReady)
.append(",isTransient=").append(isTransient)
.append(",statusLabel=").append(statusLabel);
}
@@ -170,6 +233,8 @@
}
WifiState other = (WifiState) o;
return Objects.equals(other.ssid, ssid)
+ && other.wifiGenerationVersion == wifiGenerationVersion
+ && other.isReady == isReady
&& other.isTransient == isTransient
&& TextUtils.equals(other.statusLabel, statusLabel);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 92a8d84..e872cd9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -32,6 +32,11 @@
public class Utils {
/**
+ * An int extra specifying a slot ID.
+ */
+ public static final String EXTRA_SLOT_ID = "slot_id";
+
+ /**
* Allows lambda iteration over a list. It is done in reverse order so it is safe
* to add or remove items during the iteration. Skips over null items.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
old mode 100644
new mode 100755
index 2224c9c..61de866
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
@@ -97,7 +97,14 @@
protected boolean registerListenerImpl(SensorEventListener listener,
Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs,
int reservedFlags) {
+ if ( sensor == null ) {
+ Log.e(TAG, "sensor cannot be null \n" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
mHandler.post(() -> {
+ if ( sensor == null ) {
+ Log.e(TAG, "sensor cannot be null");
+ }
if (!mInner.registerListener(listener, sensor, delayUs, maxReportLatencyUs, handler)) {
Log.e(TAG, "Registering " + listener + " for " + sensor + " failed.");
}
@@ -146,6 +153,9 @@
throw new IllegalArgumentException("sensor cannot be null");
}
mHandler.post(() -> {
+ if ( sensor == null ) {
+ Log.e(TAG, "sensor cannot be null");
+ }
if (!mInner.requestTriggerSensor(listener, sensor)) {
Log.e(TAG, "Requesting " + listener + " for " + sensor + " failed.");
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 81e2c22..9a03d89 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,6 +38,10 @@
android.test.runner \
telephony-common \
android.test.base \
+ android.car \
+ android.car.userlib \
+ telephony-ext \
+ ims-common
LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index bfb0e15..aaf65bb 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -53,6 +53,7 @@
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java
index a2a20a95..d17fd79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSCarrierGroupTest.java
@@ -185,6 +185,6 @@
spiedCarrierGroup.setMobileDataIndicators(
mock(NetworkController.IconState.class),
mock(NetworkController.IconState.class),
- 0, 0, true, true, "", "", true, 0, true);
+ 0, 0, true, true, 0, "", "", true, 0, true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index d4688d7..f29d6a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -69,4 +69,5 @@
// Verify Settings wasn't launched.
verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
index 85f6033..c574eaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -122,8 +122,8 @@
boolean wide = true;
int subId = 5;
boolean roaming = true;
- mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, typeDescription,
- description, wide, subId, roaming);
+ mHandler.setMobileDataIndicators(status, qs, type, qsType, in, out, 0,
+ typeDescription, description, wide, subId, roaming);
waitForCallbacks();
ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
@@ -138,7 +138,9 @@
ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class);
Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(),
qsArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(), inArg.capture(),
- outArg.capture(), typeContentArg.capture(), descArg.capture(), wideArg.capture(),
+ outArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ typeContentArg.capture(), descArg.capture(), wideArg.capture(),
subIdArg.capture(), eq(roaming));
assertEquals(status, statusArg.getValue());
assertEquals(qs, qsArg.getValue());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FiveGServiceClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FiveGServiceClientTest.java
new file mode 100644
index 0000000..6c1633a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FiveGServiceClientTest.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.os.RemoteException;
+import android.telephony.SubscriptionInfo;
+import android.util.Log;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codeaurora.internal.IExtTelephony;
+import org.codeaurora.internal.INetworkCallback;
+import org.codeaurora.internal.NrConfigType;
+import org.codeaurora.internal.NrIconType;
+import org.codeaurora.internal.ServiceUtil;
+import org.codeaurora.internal.Status;
+import org.codeaurora.internal.Token;
+import org.codeaurora.internal.UpperLayerIndInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.android.systemui.statusbar.policy.FiveGServiceClient;
+import com.android.systemui.statusbar.policy.FiveGServiceClient.FiveGServiceState;
+import com.android.systemui.statusbar.policy.TelephonyIcons;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class FiveGServiceClientTest extends NetworkControllerBaseTest {
+ private final static String TAG = "FiveGServiceClientTest";
+ private FiveGServiceClient mFiveGServiceClient;
+ protected INetworkCallback mCallback;
+
+ Token mToken;
+ Status mSuccessStatus;
+ Status mFailStatus;
+ private int mPhoneId;
+
+ @Before
+ public void setupCallback() {
+ mPhoneId = 0;
+ mToken = new Token(0);
+ mSuccessStatus = new Status(Status.SUCCESS);
+ mFailStatus = new Status(Status.FAILURE);
+ mFiveGServiceClient = mNetworkController.mFiveGServiceClient;
+ mCallback = mFiveGServiceClient.mCallback;
+
+ }
+
+ @Test
+ public void testSignalStrength() {
+ int rsrp = -50;
+ int level = 3;
+ //Success status case
+ org.codeaurora.internal.SignalStrength signalStrength =
+ new org.codeaurora.internal.SignalStrength(rsrp, rsrp);
+ updateSignalStrength(mPhoneId, mToken, mSuccessStatus, signalStrength);
+
+ FiveGServiceState fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getSignalLevel(), level);
+
+ //Failure status case
+ rsrp = org.codeaurora.internal.SignalStrength.INVALID;
+ signalStrength =
+ new org.codeaurora.internal.SignalStrength(rsrp, rsrp);
+ updateSignalStrength(mPhoneId, mToken, mFailStatus, signalStrength);
+ fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getSignalLevel(), level);
+ }
+
+ @Test
+ public void test5gConfigInfo() {
+ //Success status case
+ NrConfigType type = new NrConfigType(NrConfigType.SA_CONFIGURATION);
+ update5gConfigInfo(mPhoneId, mToken, mSuccessStatus, type);
+ FiveGServiceState fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getNrConfigType(), NrConfigType.SA_CONFIGURATION);
+
+ //Failure status case
+ type = new NrConfigType(NrConfigType.NSA_CONFIGURATION);
+ update5gConfigInfo(mPhoneId, mToken, mFailStatus, type);
+ fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getNrConfigType(), NrConfigType.SA_CONFIGURATION);
+ }
+
+ @Test
+ public void testNrIconType() {
+ //Success status case
+ NrIconType nrIconType = new NrIconType(NrIconType.TYPE_5G_BASIC);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ FiveGServiceState fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getNrIconType(), NrIconType.TYPE_5G_BASIC);
+
+ //Failure status case
+ nrIconType = new NrIconType(NrIconType.TYPE_NONE);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ assertEquals(fiveGState.getNrIconType(), NrIconType.TYPE_5G_BASIC);
+ }
+
+ @Test
+ public void test5GBasicIcon() {
+ NrConfigType configType = new NrConfigType(NrConfigType.NSA_CONFIGURATION);
+ update5gConfigInfo(mPhoneId, mToken, mSuccessStatus, configType);
+
+ /**
+ * Verify that 5G Basic icon is shown when
+ * NrConfigType is NSA_CONFIGURATION and
+ * NrIconType is TYPE_5G_BASIC
+ */
+ NrIconType nrIconType = new NrIconType(NrIconType.TYPE_5G_BASIC);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ verifyIcon(TelephonyIcons.ICON_5G_BASIC);
+
+ /**
+ * Verify that 5G Basic icon is not shown when
+ * NrConfigType is NSA_CONFIGURATION and
+ * NrIconType is TYPE_NONE
+ */
+ nrIconType = new NrIconType(NrIconType.TYPE_NONE);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ verifyIcon(0);
+ }
+
+ @Test
+ public void test5GUWBIcon() {
+ NrConfigType configType = new NrConfigType(NrConfigType.NSA_CONFIGURATION);
+ update5gConfigInfo(mPhoneId, mToken, mSuccessStatus, configType);
+
+ /**
+ * Verify that 5G UWB icon is shown when
+ * NrConfigType is NSA_CONFIGURATION and
+ * NrIconType is TYPE_5G_UWB
+ */
+ NrIconType nrIconType = new NrIconType(NrIconType.TYPE_5G_UWB);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ verifyIcon(TelephonyIcons.ICON_5G_UWB);
+
+ /**
+ * Verify that 5G UWB icon is not shown when
+ * NrConfigType is NSA_CONFIGURATION and
+ * NrIconType is TYPE_NONE
+ */
+ nrIconType = new NrIconType(NrIconType.TYPE_NONE);
+ updateNrIconType(mPhoneId, mToken, mSuccessStatus, nrIconType);
+ verifyIcon(0);
+ }
+
+ public void updateSignalStrength(int phoneId, Token token, Status status,
+ org.codeaurora.internal.SignalStrength signalStrength) {
+ Log.d(TAG, "Sending SignalStrength");
+ try {
+ mCallback.onSignalStrength(phoneId, token, status, signalStrength);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void update5gConfigInfo(int phoneId, Token token, Status status,
+ NrConfigType nrConfigType) {
+ Log.d(TAG, "Sending 5gConfigInfo");
+ try {
+ mCallback.on5gConfigInfo(phoneId, token, status, nrConfigType);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void updateNrIconType(int phoneId, Token token, Status status, NrIconType nrIconType) {
+ Log.d(TAG, "Sending NrIconType");
+ try {
+ mCallback.onNrIconType(phoneId, token, status, nrIconType);
+ } catch ( RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void verifyIcon(int resIcon) {
+ FiveGServiceState fiveGState = mFiveGServiceClient.getCurrentServiceState(mPhoneId);
+ int dataType = fiveGState.getIconGroup().mDataType;
+ assertEquals(dataType, resIcon);
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index c03f07e..ca7044f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -377,6 +377,7 @@
iconArg.capture(),
anyInt(),
typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean());
IconState iconState = iconArg.getValue();
int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
@@ -409,7 +410,9 @@
iconArg.capture(),
any(),
typeIconArg.capture(),
- anyInt(), anyBoolean(), anyBoolean(), anyString(), anyString(), anyBoolean(),
+ anyInt(), anyBoolean(), anyBoolean(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ anyString(), anyString(), anyBoolean(),
anyInt(), eq(roaming));
IconState iconState = iconArg.getValue();
@@ -452,6 +455,7 @@
qsTypeIconArg.capture(),
dataInArg.capture(),
dataOutArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
typeContentDescriptionArg.capture(),
anyString(), anyBoolean(), anyInt(), anyBoolean());
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 3067beb..eca37da 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -116,6 +116,7 @@
"dnsresolver_aidl_interface-V2-java",
"netd_aidl_interface-java",
"netd_event_listener_interface-java",
+ "vendor.qti.hardware.servicetracker-V1.0-java",
],
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 208b638..c529f3a 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -88,6 +88,7 @@
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final String BLUETOOTH_PRIVILEGED_PERM = android.Manifest.permission.BLUETOOTH_PRIVILEGED;
private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
@@ -199,6 +200,7 @@
// synchronize with broadcast receiver.
private boolean mQuietEnableExternal;
private boolean mEnableExternal;
+ private boolean mEnableBLE;
// Map of apps registered to keep BLE scanning on.
private Map<IBinder, ClientDeathRecipient> mBleApps =
@@ -312,9 +314,11 @@
mContext.getPackageName());
}
} else if (mEnableExternal) {
+ if (st!= BluetoothAdapter.STATE_ON && isBluetoothPersistedStateOn()) {
sendEnableMsg(mQuietEnableExternal,
BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
mContext.getPackageName());
+ }
}
}
}
@@ -384,6 +388,7 @@
mBinding = false;
mUnbinding = false;
mEnable = false;
+ mEnableBLE = false;
mState = BluetoothAdapter.STATE_OFF;
mQuietEnableExternal = false;
mEnableExternal = false;
@@ -731,11 +736,13 @@
private void disableBleScanMode() {
try {
mBluetoothLock.writeLock().lock();
- if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
+ if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON) && (!isBluetoothPersistedStateOnBluetooth())) {
if (DBG) {
Slog.d(TAG, "Reseting the mEnable flag for clean disable");
}
- mEnable = false;
+ if (!mEnableExternal) {
+ mEnable = false;
+ }
}
} catch (RemoteException e) {
Slog.e(TAG, "getState()", e);
@@ -752,6 +759,7 @@
checkPackage(callingUid, packageName);
}
ClientDeathRecipient r = mBleApps.get(token);
+ int st = BluetoothAdapter.STATE_OFF;
if (r == null && enable) {
ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName);
try {
@@ -771,6 +779,21 @@
Slog.d(TAG, "Unregistered for death of " + packageName);
}
}
+ if (enable) {
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth == null ||
+ (mBluetooth.getState() != BluetoothAdapter.STATE_BLE_ON &&
+ mBluetooth.getState() != BluetoothAdapter.STATE_TURNING_ON &&
+ mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
+ mEnableBLE = true;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG,"Unable to call getState", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
+ }
int appCount = mBleApps.size();
if (DBG) {
Slog.d(TAG, appCount + " registered Ble Apps");
@@ -778,8 +801,22 @@
if (appCount == 0 && mEnable) {
disableBleScanMode();
}
- if (appCount == 0 && !mEnableExternal) {
- sendBrEdrDownCallback();
+ if(appCount == 0) {
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null) {
+ st = mBluetooth.getState();
+ }
+ if (!mEnableExternal || (st == BluetoothAdapter.STATE_BLE_ON)) {
+ if (DBG) Slog.d(TAG, "Move to BT state OFF");
+ sendBrEdrDownCallback();
+ mEnableExternal = false;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
}
return appCount;
}
@@ -810,8 +847,23 @@
Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!");
return;
}
- if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
+ int st = mBluetooth.getState();
+ if (st != BluetoothAdapter.STATE_BLE_ON) {
+ if (DBG) Slog.v(TAG, "onBluetoothServiceUp: state isn't BLE_ON: " +
+ BluetoothAdapter.nameForState(st));
+ return;
+ }
+ if (isAirplaneModeOn() && !mEnableExternal) {
+ addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ mContext.getPackageName(), false);
+
+ mBluetooth.onBrEdrDown();
+ mEnable = false;
+ mEnableExternal = false;
+ } else if (isBluetoothPersistedStateOnBluetooth() ||
+ mEnableExternal) {
// This triggers transition to STATE_ON
+ mBluetooth.updateQuietModeStatus(mQuietEnable);
mBluetooth.onLeServiceUp();
persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
}
@@ -839,7 +891,9 @@
if (isBleAppPresent()) {
// Need to stay at BLE ON. Disconnect all Gatt connections
try {
- mBluetoothGatt.unregAll();
+ if (mBluetoothGatt != null) {
+ mBluetoothGatt.unregAll();
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Unable to disconnect all apps.", e);
}
@@ -931,7 +985,11 @@
synchronized (mReceiver) {
mQuietEnableExternal = false;
- mEnableExternal = true;
+ if (!mEnableBLE) {
+ mEnableExternal = true;
+ } else {
+ mEnableBLE = false;
+ }
// waive WRITE_SECURE_SETTINGS permission check
sendEnableMsg(false,
BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
@@ -965,16 +1023,40 @@
}
if (DBG) {
- Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding);
+ Slog.d(TAG, "disable(" + packageName + "): mBluetooth = "
+ + mBluetooth + " mBinding = " + mBinding);
}
synchronized (mReceiver) {
if (persist) {
persistBluetoothSetting(BLUETOOTH_OFF);
- }
- mEnableExternal = false;
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
+ mEnableExternal = false;
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
packageName);
+ } else {
+ /* It means disable is called by shutdown thread */
+ synchronized (this) {
+ clearBleApps();
+ }
+
+ try {
+ mBluetoothLock.readLock().lock();
+ mEnableExternal = false;
+ if (mBluetooth != null) {
+ if(mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ mEnable = false;
+ mBluetooth.onBrEdrDown();
+ } else {
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
+ packageName);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to initiate disable", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
+ }
}
return true;
}
@@ -1092,14 +1174,29 @@
return mBluetoothGatt;
}
+ public boolean isBluetoothAvailableForBinding() {
+ try {
+ mBluetoothLock.writeLock().lock();
+ if (mBluetooth != null && ((mBluetooth.getState() == BluetoothAdapter.STATE_ON) ||
+ (mBluetooth.getState() == BluetoothAdapter.STATE_TURNING_ON))) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getState()", e);
+ } finally {
+ mBluetoothLock.writeLock().unlock();
+ }
+ return false;
+ }
+
@Override
public boolean bindBluetoothProfileService(int bluetoothProfile,
IBluetoothProfileServiceConnection proxy) {
- if (!mEnable) {
- if (DBG) {
- Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile
- + ", while Bluetooth was disabled");
- }
+ if (isBluetoothAvailableForBinding() == false) {
+ Slog.w(TAG, "bindBluetoothProfileService:Trying to bind to profile: "
+ + bluetoothProfile + ", while Bluetooth is disabled");
return false;
}
synchronized (mProfileServices) {
@@ -1122,6 +1219,8 @@
mProfileServices.put(new Integer(bluetoothProfile), psc);
}
+ else
+ Slog.w(TAG, "psc is not null in bindBluetoothProfileService");
}
// Introducing a delay to give the client app time to prepare
@@ -1139,16 +1238,20 @@
Integer profile = new Integer(bluetoothProfile);
ProfileServiceConnections psc = mProfileServices.get(profile);
if (psc == null) {
+ Slog.e(TAG, "unbindBluetoothProfileService: psc is null, returning");
return;
}
+ Slog.w(TAG, "unbindBluetoothProfileService: calling psc.removeProxy");
psc.removeProxy(proxy);
if (psc.isEmpty()) {
- // All prxoies are disconnected, unbind with the service.
+ // All proxies are disconnected, unbind with the service.
try {
mContext.unbindService(psc);
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
}
+ Slog.w(TAG, "psc.isEmpty is true, removing psc entry for profile "
+ + profile);
mProfileServices.remove(profile);
}
}
@@ -1282,6 +1385,13 @@
Slog.e(TAG, "Unable to connect to proxy", e);
}
} else {
+ if (isBluetoothAvailableForBinding() == false) {
+ Slog.w(TAG, "addProxy: Trying to bind to profile: " + mClassName +
+ ", while Bluetooth is disabled");
+ mProxies.unregister(proxy);
+ return;
+ }
+
if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
msg.obj = this;
@@ -1299,6 +1409,9 @@
Slog.e(TAG, "Unable to disconnect proxy", e);
}
}
+
+ Slog.w(TAG, "removing the proxy, count is "
+ + mProxies.getRegisteredCallbackCount());
} else {
Slog.w(TAG, "Trying to remove a null proxy");
}
@@ -1310,7 +1423,7 @@
}
private boolean isEmpty() {
- return mProxies.getRegisteredCallbackCount() == 0;
+ return (mProxies != null && mProxies.getRegisteredCallbackCount() == 0);
}
@Override
@@ -1348,13 +1461,11 @@
@Override
public void onServiceDisconnected(ComponentName className) {
- if (mService == null) {
- return;
- }
+ if (mService == null) return;
try {
mService.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
- Log.e(TAG, "error unlinking to death", e);
+ Slog.e(TAG, "Unable to unlinkToDeath", e);
}
mService = null;
mClassName = null;
@@ -1386,6 +1497,12 @@
Slog.w(TAG, "Profile service for profile: " + mClassName + " died.");
}
onServiceDisconnected(mClassName);
+
+ if (isBluetoothAvailableForBinding() == false) {
+ Slog.w(TAG, "binderDied: Trying to bind to profile: " + mClassName +
+ ", while Bluetooth is disabled");
+ return;
+ }
// Trigger rebind
Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
msg.obj = this;
@@ -1507,6 +1624,41 @@
return mName;
}
+ public boolean factoryReset() {
+ final int callingUid = Binder.getCallingUid();
+ final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
+
+ if (!callerSystem) {
+ if (!checkIfCallerIsForegroundUser()) {
+ Slog.w(TAG, "factoryReset(): not allowed for non-active and non system user");
+ return false;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ BLUETOOTH_PRIVILEGED_PERM, "Need BLUETOOTH PRIVILEGED permission");
+ }
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ // Clear registered LE apps to force shut-off
+ clearBleApps();
+ try {
+ if (mBluetooth == null) {
+ mEnable = true;
+ handleEnable(mQuietEnable);
+ } else if (mBluetooth != null &&
+ (mBluetooth.getState() == BluetoothAdapter.STATE_OFF)) {
+ mEnable = true;
+ mBluetooth.factoryReset();
+ handleEnable(mQuietEnable);
+ } else if (mBluetooth != null){
+ return mBluetooth.factoryReset();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "factoryReset(): Unable to do factoryReset.", e);
+ return false;
+ }
+ return true;
+ }
+
private class BluetoothServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName componentName, IBinder service) {
String name = componentName.getClassName();
@@ -1516,6 +1668,7 @@
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
} else if (name.equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
@@ -1601,6 +1754,7 @@
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
+ mQuietEnable = (msg.arg1 == 1);
// Use service interface to get the exact state
try {
mBluetoothLock.readLock().lock();
@@ -1608,8 +1762,13 @@
int state = mBluetooth.getState();
if (state == BluetoothAdapter.STATE_BLE_ON) {
Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
+ mBluetooth.updateQuietModeStatus(mQuietEnable);
mBluetooth.onLeServiceUp();
+
+ // waive WRITE_SECURE_SETTINGS permission check
+ long callingIdentity = Binder.clearCallingIdentity();
persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ Binder.restoreCallingIdentity(callingIdentity);
break;
}
}
@@ -1619,7 +1778,6 @@
mBluetoothLock.readLock().unlock();
}
- mQuietEnable = (msg.arg1 == 1);
if (mBluetooth == null) {
handleEnable(mQuietEnable);
} else {
@@ -1628,7 +1786,7 @@
// the previous Bluetooth process has exited. The
// waiting period has three components:
// (a) Wait until the local state is STATE_OFF. This
- // is accomplished by "waitForOnOff(false, true)".
+ // is accomplished by "waitForMonitoredOnOff(false, true)".
// (b) Wait until the STATE_OFF state is updated to
// all components.
// (c) Wait until the Bluetooth process exits, and
@@ -1638,7 +1796,17 @@
// message. On slower devices, that delay needs to be
// on the order of (2 * SERVICE_RESTART_TIME_MS).
//
- waitForOnOff(false, true);
+ // Wait for (a) is required only when Bluetooth is being
+ // turned off.
+ int state;
+ try {
+ state = mBluetooth.getState();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getState()", e);
+ break;
+ }
+ if(state == BluetoothAdapter.STATE_TURNING_OFF || state == BluetoothAdapter.STATE_BLE_TURNING_OFF)
+ waitForMonitoredOnOff(false, true);
Message restartMsg =
mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
@@ -1651,10 +1819,26 @@
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
if (mEnable && mBluetooth != null) {
- waitForOnOff(true, false);
+ waitForMonitoredOnOff(true, false);
+
+ try {
+ mBluetoothLock.readLock().lock();
+ if((mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) &&
+ ((isBluetoothPersistedStateOnBluetooth() ||
+ !isBleAppPresent()))) {
+ Message disableMsg =
+ mHandler.obtainMessage(MESSAGE_DISABLE);
+ mHandler.sendMessageDelayed(disableMsg, 100);
+ break;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to initiate disable", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
mEnable = false;
handleDisable();
- waitForOnOff(false, false);
+ waitForMonitoredOnOff(false, false);
} else {
mEnable = false;
handleDisable();
@@ -1717,11 +1901,14 @@
break;
}
case MESSAGE_BIND_PROFILE_SERVICE: {
+ Slog.w(TAG, "MESSAGE_BIND_PROFILE_SERVICE");
ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
if (psc == null) {
+ Slog.w(TAG, "psc is null, breaking");
break;
}
+ Slog.w(TAG, "Calling psc.bindService from MESSAGE_BIND_PROFILE_SERVICE");
psc.bindService();
break;
}
@@ -1740,9 +1927,6 @@
break;
} // else must be SERVICE_IBLUETOOTH
- //Remove timeout
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-
mBinding = false;
mBluetoothBinder = service;
mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));
@@ -1783,9 +1967,9 @@
}
if (!mEnable) {
- waitForOnOff(true, false);
+ waitForMonitoredOnOff(true, false);
handleDisable();
- waitForOnOff(false, false);
+ waitForMonitoredOnOff(false, false);
}
break;
}
@@ -1806,8 +1990,14 @@
== BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError(false);
}
- if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState
- == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) {
+ if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
+ (newState == BluetoothAdapter.STATE_OFF) &&
+ (mBluetooth != null) && mEnable) {
+ persistBluetoothSetting(BLUETOOTH_OFF);
+ }
+ if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
+ (newState == BluetoothAdapter.STATE_BLE_ON) &&
+ (mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError(true);
}
// If we tried to enable BT while BT was in the process of shutting down,
@@ -1817,7 +2007,8 @@
== BluetoothAdapter.STATE_OFF)) {
if (mEnable) {
Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
- waitForOnOff(false, true);
+ mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+ waitForMonitoredOnOff(false, true);
Message restartMsg =
mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
@@ -1940,7 +2131,7 @@
mState = BluetoothAdapter.STATE_TURNING_ON;
}
- waitForOnOff(true, false);
+ waitForMonitoredOnOff(true, false);
if (mState == BluetoothAdapter.STATE_TURNING_ON) {
bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
@@ -1950,27 +2141,32 @@
// disable
addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH,
mContext.getPackageName(), false);
+
+ clearBleApps();
+
handleDisable();
// Pbap service need receive STATE_TURNING_OFF intent to close
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
- boolean didDisableTimeout = !waitForOnOff(false, true);
+ boolean didDisableTimeout = !waitForMonitoredOnOff(false, true);
bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
BluetoothAdapter.STATE_OFF);
sendBluetoothServiceDownCallback();
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
+ if(!didDisableTimeout) {
+ try {
+ mBluetoothLock.writeLock().lock();
+ if (mBluetooth != null) {
+ mBluetooth = null;
+ // Unbind
+ mContext.unbindService(mConnection);
+ }
+ mBluetoothGatt = null;
+ } finally {
+ mBluetoothLock.writeLock().unlock();
}
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
}
//
@@ -1980,6 +2176,7 @@
//
if (didDisableTimeout) {
SystemClock.sleep(3000);
+ mHandler.removeMessages(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
} else {
SystemClock.sleep(100);
}
@@ -2124,6 +2321,7 @@
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
}
@@ -2145,8 +2343,10 @@
sendBluetoothServiceDownCallback();
unbindAndFinish();
sendBleStateChanged(prevState, newState);
- // Don't broadcast as it has already been broadcast before
- isStandardBroadcast = false;
+ if (prevState != BluetoothAdapter.STATE_TURNING_ON) {
+ // Don't broadcast as it has already been broadcast before
+ isStandardBroadcast = false;
+ }
} else if (!intermediate_off) {
// connect to GattService
@@ -2203,6 +2403,7 @@
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
}
}
@@ -2214,7 +2415,7 @@
*/
private boolean waitForOnOff(boolean on, boolean off) {
int i = 0;
- while (i < 10) {
+ while (i < 16) {
try {
mBluetoothLock.readLock().lock();
if (mBluetooth == null) {
@@ -2240,13 +2441,66 @@
mBluetoothLock.readLock().unlock();
}
if (on || off) {
+ SystemClock.sleep(500);
+ } else {
+ SystemClock.sleep(30);
+ }
+ i++;
+ }
+ Slog.e(TAG,"waitForOnOff time out");
+ return false;
+ }
+
+ /**
+ * if on is true, wait for state become ON
+ * if off is true, wait for state become OFF
+ * if both on and off are false, wait for state not ON
+ */
+ private boolean waitForMonitoredOnOff(boolean on, boolean off) {
+ int i = 0;
+ while (i < 10) {
+ synchronized(mConnection) {
+ try {
+ if (mBluetooth == null) break;
+ if (on) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_BLE_TURNING_ON,
+ BluetoothAdapter.STATE_BLE_ON);
+ if (mBluetoothGatt != null) {
+ Slog.d(TAG,"GattService is connected, execute waitForOnOff");
+ boolean ret = waitForOnOff(on, off);
+ return ret;
+ } else {
+ Slog.d(TAG,
+ "GattService connect in progress, return to avoid timeout");
+ return true;
+ }
+ }
+ } else if (off) {
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+ if (mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+ BluetoothAdapter.STATE_BLE_ON);
+ boolean ret = waitForOnOff(on, off);
+ return ret;
+ }
+ } else {
+ if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "getState()", e);
+ break;
+ }
+ }
+ if (on || off) {
SystemClock.sleep(300);
} else {
SystemClock.sleep(50);
}
i++;
}
- Slog.e(TAG, "waitForOnOff time out");
+ Slog.e(TAG,"waitForMonitoredOnOff time out");
return false;
}
@@ -2300,29 +2554,10 @@
mBluetoothLock.readLock().unlock();
}
- SystemClock.sleep(500);
-
- // disable
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR,
- mContext.getPackageName(), false);
- handleDisable();
-
- waitForOnOff(false, true);
+ waitForMonitoredOnOff(false, true);
sendBluetoothServiceDownCallback();
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
mState = BluetoothAdapter.STATE_OFF;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ce0e9e7..ee8e3f1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
@@ -46,6 +47,7 @@
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
+import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -61,6 +63,7 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.telephony.SubscriptionInfo;
import android.net.CaptivePortal;
import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
@@ -106,6 +109,7 @@
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.StringNetworkSpecifier;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.Uri;
@@ -143,6 +147,8 @@
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -271,6 +277,7 @@
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
+ protected int mNonDefaultSubscriptionLingerDelayMs;
// How long to delay to removal of a pending intent based request.
// See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
@@ -549,6 +556,14 @@
*/
private static final int PROVISIONING_NOTIFICATION_HIDE = 0;
+ private static final int EVENT_UPDATE_TCP_BUFFER_FOR_5G = 160;
+
+ /**
+ * Used to save the active subscription ID info.
+ * arg1 = subId
+ */
+ private static final int EVENT_UPDATE_ACTIVE_DATA_SUBID = 161;
+
private static String eventName(int what) {
return sMagicDecoderRing.get(what, Integer.toString(what));
}
@@ -558,6 +573,17 @@
.asInterface(ServiceManager.getService("dnsresolver"));
}
+ private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ if (subId != mPreferredSubId) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_UPDATE_ACTIVE_DATA_SUBID, subId, 0));
+ }
+ }
+ };
+
+ private int mPreferredSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
/** Handler thread used for both of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -592,6 +618,7 @@
private Set<String> mWolSupportedInterfaces;
private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
private KeepaliveTracker mKeepaliveTracker;
private NetworkNotificationManager mNotifier;
@@ -972,6 +999,7 @@
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
+ mNonDefaultSubscriptionLingerDelayMs = 5_000;
mContext = checkNotNull(context, "missing Context");
mNMS = checkNotNull(netManager, "missing INetworkManagementService");
@@ -986,6 +1014,8 @@
mNetd = netd;
mKeyStore = KeyStore.getInstance();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mSubscriptionManager = SubscriptionManager.from(mContext);
+ mTelephonyManager.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
// To ensure uid rules are synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
@@ -2313,12 +2343,24 @@
@VisibleForTesting
protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
+ private void updateTcpBufferSizes(NetworkAgentInfo nai) {
+ if (isDefaultNetwork(nai) == false) {
+ return;
+ }
+
+ String tcpBufferSizes = nai.linkProperties.getTcpBufferSizes();
+ if(nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)){
+ tcpBufferSizes = NetPluginDelegate.get5GTcpBuffers(tcpBufferSizes,
+ nai.networkCapabilities.getNetworkSpecifier());
+ }
+ updateTcpBufferSizes(tcpBufferSizes);
+ }
+
private void updateTcpBufferSizes(String tcpBufferSizes) {
String[] values = null;
if (tcpBufferSizes != null) {
values = tcpBufferSizes.split(",");
}
-
if (values == null || values.length != 6) {
if (DBG) log("Invalid tcpBufferSizes string: " + tcpBufferSizes +", using defaults");
tcpBufferSizes = DEFAULT_TCP_BUFFER_SIZES;
@@ -3300,6 +3342,7 @@
if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
return false;
}
+
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
// Background requests don't affect lingering.
@@ -3308,8 +3351,10 @@
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then it is needed.
- if (nri.request.isRequest() && nai.satisfies(nri.request) &&
- (nai.isSatisfyingRequest(nri.request.requestId) ||
+ if (nri.request.isRequest() && nai.satisfies(nri.request)
+ && satisfiesMobileMultiNetworkDataCheck(nai.networkCapabilities,
+ nri.request.networkCapabilities)
+ && (nai.isSatisfyingRequest(nri.request.requestId) ||
// Note that this catches two important cases:
// 1. Unvalidated cellular will not be reaped when unvalidated WiFi
// is currently satisfying the request. This is desirable when
@@ -3317,8 +3362,9 @@
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- getNetworkForRequest(nri.request.requestId).getCurrentScore() <
- nai.getCurrentScoreAsValidated())) {
+ ((getNetworkForRequest(nri.request.requestId) != null)
+ && (getNetworkForRequest(nri.request.requestId).getCurrentScore() <
+ nai.getCurrentScoreAsValidated())))) {
return false;
}
}
@@ -3955,6 +4001,7 @@
}
case EVENT_SYSTEM_READY: {
mMultipathPolicyTracker.start();
+ NetPluginDelegate.registerHandler(mHandler);
break;
}
case EVENT_REVALIDATE_NETWORK: {
@@ -3977,6 +4024,12 @@
case EVENT_TIMEOUT_NOTIFICATION:
mNotifier.clearNotification(msg.arg1, NotificationType.LOGGED_IN);
break;
+ case EVENT_UPDATE_TCP_BUFFER_FOR_5G:
+ handleUpdateTCPBuffersfor5G();
+ break;
+ case EVENT_UPDATE_ACTIVE_DATA_SUBID:
+ handleUpdateActiveDataSubId(msg.arg1);
+ break;
}
}
}
@@ -6346,7 +6399,15 @@
final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
final boolean satisfies = newNetwork.satisfies(nri.request);
- if (newNetwork == currentNetwork && satisfies) {
+ boolean satisfiesMobileMultiNetworkCheck = false;
+
+ if (satisfies) {
+ satisfiesMobileMultiNetworkCheck = satisfiesMobileMultiNetworkDataCheck(
+ newNetwork.networkCapabilities,
+ nri.request.networkCapabilities);
+ }
+
+ if (newNetwork == currentNetwork && satisfiesMobileMultiNetworkCheck) {
if (VDBG) {
log("Network " + newNetwork.name() + " was already satisfying" +
" request " + nri.request.requestId + ". No change.");
@@ -6357,7 +6418,7 @@
// check if it satisfies the NetworkCapabilities
if (VDBG) log(" checking if request is satisfied: " + nri.request);
- if (satisfies) {
+ if (satisfiesMobileMultiNetworkCheck) {
// next check if it's better than any current network we're using for
// this request
if (VDBG || DDBG) {
@@ -6365,14 +6426,24 @@
(currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
", newScore = " + score);
}
- if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {
+ if (currentNetwork == null ||
+ isBestMobileMultiNetwork(currentNetwork,
+ currentNetwork.networkCapabilities,
+ newNetwork,
+ newNetwork.networkCapabilities,
+ nri.request.networkCapabilities) ||
+ currentNetwork.getCurrentScore() < score) {
if (VDBG) log("rematch for " + newNetwork.name());
if (currentNetwork != null) {
if (VDBG || DDBG){
log(" accepting network in place of " + currentNetwork.name());
}
currentNetwork.removeRequest(nri.request.requestId);
- currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
+ if (satisfiesMobileNetworkDataCheck(currentNetwork.networkCapabilities)) {
+ currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);
+ } else {
+ currentNetwork.lingerRequest(nri.request, now, mNonDefaultSubscriptionLingerDelayMs);
+ }
affectedNetworks.add(currentNetwork);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
@@ -6426,10 +6497,25 @@
// a) be requested and b) change is NET_CAPABILITY_TRUSTED,
// so this code is only incorrect for a network that loses
// the TRUSTED capability, which is a rare case.
- callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
+ // Linger the non-DDS network requests and do not send LOST
+ // callback, since ideally callback LOSING is sent if lingering
+ if (satisfiesMobileNetworkDataCheck(newNetwork.networkCapabilities)) {
+ callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
+ } else {
+ newNetwork.lingerRequest(nri.request, now, mNonDefaultSubscriptionLingerDelayMs);
+ }
}
}
if (isNewDefault) {
+ // restore permission to actual value if it becomes the default network again..
+ if (!newNetwork.isVPN()) {
+ try {
+ mNMS.setNetworkPermission(newNetwork.network.netId,
+ getNetworkPermission(newNetwork.networkCapabilities));
+ } catch (RemoteException e) {
+ loge("Exception in setNetworkPermission: " + e);
+ }
+ }
updateDataActivityTracking(newNetwork, oldDefaultNetwork);
// Notify system services that this network is up.
makeDefault(newNetwork);
@@ -6462,6 +6548,16 @@
processListenRequests(newNetwork, false);
}
+ if ((satisfiesMobileNetworkDataCheck(newNetwork.networkCapabilities) == false) &&
+ !newNetwork.isVPN()) {
+ // Force trigger permission change on non-DDS network to close all live connections
+ try {
+ mNMS.setNetworkPermission(newNetwork.network.netId,
+ INetd.PERMISSION_NETWORK);
+ } catch (RemoteException e) {
+ loge("Exception in setNetworkPermission: " + e);
+ }
+ }
// do this after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
@@ -7269,4 +7365,83 @@
return mTNS;
}
}
+
+ private boolean isMobileNetwork(NetworkAgentInfo nai) {
+ if (nai != null && nai.networkCapabilities != null &&
+ nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean satisfiesMobileNetworkDataCheck(NetworkCapabilities agentNc) {
+ if (agentNc != null && agentNc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ if (mPreferredSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return true;
+
+ if((agentNc.hasCapability(NET_CAPABILITY_EIMS) &&
+ (mSubscriptionManager != null &&
+ (mSubscriptionManager.getActiveSubscriptionInfoList() == null ||
+ mSubscriptionManager.getActiveSubscriptionInfoList().size()==0))) ||
+ (getIntSpecifier(agentNc.getNetworkSpecifier()) == mPreferredSubId)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean satisfiesMobileMultiNetworkDataCheck(NetworkCapabilities agentNc,
+ NetworkCapabilities requestNc) {
+ if (requestNc != null && getIntSpecifier(requestNc.getNetworkSpecifier()) < 0) {
+ return satisfiesMobileNetworkDataCheck(agentNc);
+ }
+ return true;
+ }
+
+ private int getIntSpecifier(NetworkSpecifier networkSpecifierObj) {
+ String specifierStr = null;
+ int specifier = -1;
+ if (networkSpecifierObj != null
+ && networkSpecifierObj instanceof StringNetworkSpecifier) {
+ specifierStr = ((StringNetworkSpecifier) networkSpecifierObj).specifier;
+ }
+ if (specifierStr != null && specifierStr.isEmpty() == false) {
+ try {
+ specifier = Integer.parseInt(specifierStr);
+ } catch (NumberFormatException e) {
+ specifier = -1;
+ }
+ }
+ return specifier;
+ }
+
+ private boolean isBestMobileMultiNetwork(NetworkAgentInfo currentNetwork,
+ NetworkCapabilities currentRequestNc,
+ NetworkAgentInfo newNetwork,
+ NetworkCapabilities newRequestNc,
+ NetworkCapabilities requestNc) {
+ if (isMobileNetwork(currentNetwork) &&
+ isMobileNetwork(newNetwork) &&
+ satisfiesMobileMultiNetworkDataCheck(newRequestNc, requestNc) &&
+ !satisfiesMobileMultiNetworkDataCheck(currentRequestNc, requestNc)) {
+ return true;
+ }
+ return false;
+ }
+
+ private void handleUpdateTCPBuffersfor5G() {
+ Network network = getActiveNetwork();
+ NetworkAgentInfo ntwAgent = getNetworkAgentInfoForNetwork(network);
+ if (DBG)
+ log("handleUpdateTCPBuffersfor5G nai " + ntwAgent);
+ if (ntwAgent != null)
+ updateTcpBufferSizes(ntwAgent);
+ }
+
+ private void handleUpdateActiveDataSubId(int subId) {
+ log("Setting mPreferredSubId to " + subId);
+ mPreferredSubId = subId;
+ rematchAllNetworksAndRequests(null, 0);
+ }
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 0a63bf8..8992e8b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -178,6 +178,9 @@
private AppOpsManager mAppOps;
private PackageManager mPackageManager;
+ private String mComboNlpPackageName;
+ private String mComboNlpReadyMarker;
+ private String mComboNlpScreenMarker;
private PowerManager mPowerManager;
private ActivityManager mActivityManager;
private UserManager mUserManager;
@@ -775,6 +778,13 @@
}
}
+ mComboNlpPackageName = resources.getString(
+ com.android.internal.R.string.config_comboNetworkLocationProvider);
+ if (mComboNlpPackageName != null) {
+ mComboNlpReadyMarker = mComboNlpPackageName + ".nlp:ready";
+ mComboNlpScreenMarker = mComboNlpPackageName + ".nlp:screen";
+ }
+
// bind to hardware activity recognition
boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
ActivityRecognitionHardware activityRecognitionHardware = null;
diff --git a/services/core/java/com/android/server/NetPluginDelegate.java b/services/core/java/com/android/server/NetPluginDelegate.java
new file mode 100644
index 0000000..cfb5007
--- /dev/null
+++ b/services/core/java/com/android/server/NetPluginDelegate.java
@@ -0,0 +1,240 @@
+/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *Redistribution and use in source and binary forms, with or without
+ *modification, are permitted provided that the following conditions are
+ *met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.server;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import android.os.Environment;
+import android.util.Slog;
+import android.util.Log;
+import android.os.Handler;
+import android.net.NetworkSpecifier;
+
+public class NetPluginDelegate {
+
+ private static final String TAG = "NetPluginDelegate";
+ private static final boolean LOGV = true;
+
+ private static Class tcpBufferRelay = null;
+ private static Object tcpBufferManagerObj = null;
+ private static boolean extJarAvail = true;
+
+ private static Class vendorPropRelay = null;
+ private static Object vendorPropManagerObj = null;
+ private static boolean vendorPropJarAvail = true;
+
+ /*
+ * Returns applicable TCP buffer size based on the network specifier.
+ */
+ public static String get5GTcpBuffers(String currentTcpBuffer, NetworkSpecifier sepcifier) {
+ String tcpBuffer = currentTcpBuffer;
+ if (LOGV) Slog.v(TAG, "get5GTcpBuffers");
+ if (!extJarAvail || !loadConnExtJar())
+ return currentTcpBuffer;
+ try {
+ Object ret = tcpBufferRelay.getMethod("get5GTcpBuffers",
+ String.class, NetworkSpecifier.class).invoke(
+ tcpBufferManagerObj, currentTcpBuffer, sepcifier);
+
+ if(ret !=null && (ret instanceof String)){
+ tcpBuffer = (String) ret;
+ }
+ } catch (InvocationTargetException | SecurityException | NoSuchMethodException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to invoke get5GTcpBuffers()");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "Error calling get5GTcpBuffers Method on extension jar");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ }
+ return tcpBuffer;
+ }
+
+ /*
+ * Provides the api to register a handler with the lib. This is used to send
+ * EVENT_UPDATE_TCP_BUFFER_FOR_5G message to the handler queue to take action on it.
+ */
+ public static void registerHandler(Handler mHandler) {
+ if (LOGV) Slog.v(TAG, "registerHandler");
+ if (!extJarAvail || !loadConnExtJar()) return;
+ try {
+ tcpBufferRelay.getMethod("registerHandler", Handler.class).invoke(
+ tcpBufferManagerObj, mHandler);
+ } catch (InvocationTargetException | SecurityException | NoSuchMethodException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to call registerHandler");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "Error calling registerHandler Method on extension jar");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ }
+ }
+
+ /*
+ * Dynamically loads the lib.
+ * Checks whether the required lib is avalaiblable if not disables further attempts
+ * to load it.
+ */
+ private static synchronized boolean loadConnExtJar() {
+ final String realProvider = "com.qualcomm.qti.net.connextension.TCPBufferManager";
+ final String realProviderPath = Environment.getRootDirectory().getAbsolutePath()
+ + "/framework/ConnectivityExt.jar";
+
+ if (tcpBufferRelay != null && tcpBufferManagerObj != null) {
+ return true;
+ }
+
+ extJarAvail = new File(realProviderPath).exists();
+ if (!extJarAvail) {
+ Log.w(TAG, "ConnectivityExt jar file not present");
+ return false;
+ }
+
+ if (tcpBufferRelay == null && tcpBufferManagerObj == null) {
+ if (LOGV) Slog.v(TAG, "loading ConnectivityExt jar");
+ try {
+ PathClassLoader classLoader = new PathClassLoader(realProviderPath,
+ ClassLoader.getSystemClassLoader());
+
+ tcpBufferRelay = classLoader.loadClass(realProvider);
+ tcpBufferManagerObj = tcpBufferRelay.newInstance();
+ if (LOGV) Slog.v(TAG, "ConnectivityExt jar loaded");
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to find, instantiate or access ConnectivityExt jar ");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ return false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "unable to load ConnectivityExt jar");
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Dynamically loads the lib.
+ * Checks whether the required lib is available if not disables further attempts
+ * to load it.
+ */
+ private static synchronized boolean loadVendorPropJar() {
+ final String realProvider = "com.qualcomm.qti.net.vendorpropextension.vendorPropManager";
+ final String realProviderPath = Environment.getRootDirectory().getAbsolutePath()
+ + "/framework/VendorPropExt.jar";
+ if (vendorPropRelay != null && vendorPropManagerObj != null) {
+ return true;
+ }
+
+ vendorPropJarAvail = new File(realProviderPath).exists();
+ if (!vendorPropJarAvail) {
+ Slog.w(TAG, "VendorPropExt jar file not present");
+ return false;
+ }
+
+ if (vendorPropRelay == null && vendorPropManagerObj == null) {
+ if (LOGV) Slog.v(TAG, "loading VendorPropExt jar");
+ try {
+ PathClassLoader classLoader = new PathClassLoader(realProviderPath,
+ ClassLoader.getSystemClassLoader());
+
+ vendorPropRelay = classLoader.loadClass(realProvider);
+ vendorPropManagerObj = vendorPropRelay.newInstance();
+ if (LOGV) Slog.v(TAG, "VendorPropExt jar loaded");
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ if (LOGV) {
+ Slog.e(TAG, "Failed to find, instantiate or access VendorPropExt jar ");
+ e.printStackTrace();
+ }
+ vendorPropJarAvail = false;
+ return false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Slog.e(TAG, "unable to load vendorPropExt jar");
+ e.printStackTrace();
+ }
+ vendorPropJarAvail = false;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Returns the Vendor Property Value.
+ */
+ public static String getConfig(String key, String currentConfigValue) {
+ String configValue = currentConfigValue;
+ if (!vendorPropJarAvail || !loadVendorPropJar()) {
+ return configValue;
+ }
+ try {
+ Object ret = vendorPropRelay.getMethod("getConfig",
+ String.class, String.class).invoke(
+ vendorPropManagerObj, key, currentConfigValue);
+
+ if(ret !=null && (ret instanceof String)){
+ configValue = (String) ret;
+ }
+ } catch (InvocationTargetException | SecurityException | NoSuchMethodException e) {
+ if (LOGV) {
+ Slog.e(TAG, "Failed to invoke getConfig()");
+ e.printStackTrace();
+ }
+ vendorPropJarAvail = false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Slog.e(TAG, "Error calling getConfig Method on vendorpropextension jar");
+ e.printStackTrace();
+ }
+ vendorPropJarAvail = false;
+ }
+ return configValue;
+ }
+}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9efaad8..4973dc2 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -327,7 +327,7 @@
public void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
}
- private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
+ private synchronized void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
final int length = mObservers.beginBroadcast();
try {
for (int i = 0; i < length; i++) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index b0b45f4..0975991 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -167,7 +167,7 @@
// Force an NTP fix when outdated
if (mTime.getCacheAge() >= mPollingIntervalMs) {
if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
- mTime.forceRefresh();
+ mTime.forceSync();
}
if (mTime.getCacheAge() < mPollingIntervalMs) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3916f0d..eac0add 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -143,6 +143,7 @@
import com.android.server.storage.StorageSessionController;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
+import com.android.internal.widget.ILockSettings;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -2590,8 +2591,22 @@
Slog.i(TAG, "changing encryption password...");
}
+ ILockSettings lockSettings = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
+ String currentPassword="default_password";
try {
- mVold.fdeChangePassword(type, password);
+ currentPassword = lockSettings.getPassword();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Couldn't get password" + e);
+ }
+
+ try {
+ mVold.fdeChangePassword(type, currentPassword, password);
+ try {
+ lockSettings.sanitizePassword();
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Couldn't sanitize password" + e);
+ }
return 0;
} catch (Exception e) {
Slog.wtf(TAG, e);
@@ -2853,6 +2868,24 @@
}
/*
+ * Clear disk encryption key bound to the associated token / secret pair. Removing the user
+ * binding of the Disk encryption key is done in two phases: first, this call will retrieve
+ * the disk encryption key using the provided token / secret pair and store it by
+ * encrypting it with a keymaster key not bound to the user, then fixateNewestUserKeyAuth
+ * is called to delete all other bindings of the disk encryption key.
+ */
+ @Override
+ public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+
+ try {
+ mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+
+ /*
* Delete all disk encryption token/secret pairs except the most recently added one
*/
@Override
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 83ad4e7..b470fbb 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -25,6 +25,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Debug;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.Looper;
@@ -32,6 +33,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -47,7 +49,9 @@
import java.io.File;
import java.io.FileWriter;
+import java.io.FileReader;
import java.io.IOException;
+import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -57,6 +61,8 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Date;
+import java.text.SimpleDateFormat;
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
@@ -130,6 +136,7 @@
int mPhonePid;
IActivityController mController;
boolean mAllowRestart = true;
+ SimpleDateFormat mTraceDateFormat = new SimpleDateFormat("dd_MM_HH_mm_ss.SSS");
final OpenFdMonitor mOpenFdMonitor;
/**
@@ -502,7 +509,7 @@
}
}
- static ArrayList<Integer> getInterestingNativePids() {
+ public static ArrayList<Integer> getInterestingNativePids() {
ArrayList<Integer> pids = getInterestingHalPids();
int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST);
@@ -519,6 +526,7 @@
@Override
public void run() {
boolean waitedHalf = false;
+ File initialStack = null;
while (true) {
final List<HandlerChecker> blockedCheckers;
final String subject;
@@ -579,8 +587,8 @@
// trace and wait another half.
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
- ActivityManagerService.dumpStackTraces(pids, null, null,
- getInterestingNativePids());
+ initialStack = ActivityManagerService.dumpStackTraces(pids,
+ null, null, getInterestingNativePids());
waitedHalf = true;
}
continue;
@@ -605,16 +613,66 @@
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
- final File stack = ActivityManagerService.dumpStackTraces(
+ final File finalStack = ActivityManagerService.dumpStackTraces(
pids, null, null, getInterestingNativePids());
+ //Collect Binder State logs to get status of all the transactions
+ if (Build.IS_DEBUGGABLE) {
+ binderStateRead();
+ }
+
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.
SystemClock.sleep(5000);
- // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
- doSysRq('w');
- doSysRq('l');
+ File watchdogTraces;
+ String newTracesPath = "traces_SystemServer_WDT"
+ + mTraceDateFormat.format(new Date()) + "_pid"
+ + String.valueOf(Process.myPid());
+ File tracesDir = new File(ActivityManagerService.ANR_TRACE_DIR);
+ watchdogTraces = new File(tracesDir, newTracesPath);
+ try {
+ if (watchdogTraces.createNewFile()) {
+ FileUtils.setPermissions(watchdogTraces.getAbsolutePath(),
+ 0600, -1, -1); // -rw------- permissions
+
+ // Append both traces from the first and second half
+ // to a new file, making it easier to debug Watchdog timeouts
+ // dumpStackTraces() can return a null instance, so check the same
+ if (initialStack != null) {
+ // check the last-modified time of this file.
+ // we are interested in this only it was written to in the
+ // last 5 minutes or so
+ final long age = System.currentTimeMillis()
+ - initialStack.lastModified();
+ final long FIVE_MINUTES_IN_MILLIS = 1000 * 60 * 5;
+ if (age < FIVE_MINUTES_IN_MILLIS) {
+ Slog.e(TAG, "First set of traces taken from "
+ + initialStack.getAbsolutePath());
+ appendFile(watchdogTraces, initialStack);
+ } else {
+ Slog.e(TAG, "First set of traces were collected more than "
+ + "5 minutes ago, ignoring ...");
+ }
+ } else {
+ Slog.e(TAG, "First set of traces are empty!");
+ }
+
+ if (finalStack != null) {
+ Slog.e(TAG, "Second set of traces taken from "
+ + finalStack.getAbsolutePath());
+ appendFile(watchdogTraces, finalStack);
+ } else {
+ Slog.e(TAG, "Second set of traces are empty!");
+ }
+ } else {
+ Slog.w(TAG, "Unable to create Watchdog dump file: createNewFile failed");
+ }
+ } catch (Exception e) {
+ // catch any exception that happens here;
+ // why kill the system when it is going to die anyways?
+ Slog.e(TAG, "Exception creating Watchdog dump file:", e);
+ }
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
@@ -626,16 +684,34 @@
if (mActivity != null) {
mActivity.addErrorToDropBox(
"watchdog", null, "system_server", null, null, null,
- subject, null, stack, null);
+ subject, null, finalStack, null);
}
StatsLog.write(StatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
}
- };
+ };
dropboxThread.start();
try {
dropboxThread.join(2000); // wait up to 2 seconds for it to return.
} catch (InterruptedException ignored) {}
+ // At times, when user space watchdog traces don't give an indication on
+ // which component held a lock, because of which other threads are blocked,
+ // (thereby causing Watchdog), trigger kernel panic
+ boolean crashOnWatchdog = SystemProperties
+ .getBoolean("persist.sys.crashOnWatchdog", false);
+ if (crashOnWatchdog) {
+ // Trigger the kernel to dump all blocked threads, and backtraces
+ // on all CPUs to the kernel log
+ Slog.e(TAG, "Triggering SysRq for system_server watchdog");
+ doSysRq('w');
+ doSysRq('l');
+
+ // wait until the above blocked threads be dumped into kernel log
+ SystemClock.sleep(3000);
+
+ doSysRq('c');
+ }
+
IActivityController controller;
synchronized (this) {
controller = mController;
@@ -687,6 +763,46 @@
}
}
+ private void appendFile (File writeTo, File copyFrom) {
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(copyFrom));
+ FileWriter out = new FileWriter(writeTo, true);
+ String line = null;
+
+ // Write line-by-line from "copyFrom" to "writeTo"
+ while ((line = in.readLine()) != null) {
+ out.write(line);
+ out.write('\n');
+ }
+ in.close();
+ out.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Exception while writing watchdog traces to new file!");
+ e.printStackTrace();
+ }
+ }
+
+ private void binderStateRead() {
+ try {
+ Slog.i(TAG,"Collecting Binder Transaction Status Information");
+ BufferedReader in =
+ new BufferedReader(new FileReader("/sys/kernel/debug/binder/state"));
+ FileWriter out = new FileWriter("/data/anr/BinderTraces_pid" +
+ String.valueOf(Process.myPid()) + ".txt");
+ String line = null;
+
+ // Write line-by-line
+ while ((line = in.readLine()) != null) {
+ out.write(line);
+ out.write('\n');
+ }
+ in.close();
+ out.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to collect state file", e);
+ }
+ }
+
public static final class OpenFdMonitor {
/**
* Number of FDs below the soft limit that we trigger a runtime restart at. This was
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 8e5c73bf..46ea94e 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -70,6 +70,12 @@
private static final String NAME_H2W = "h2w";
private static final String NAME_USB_AUDIO = "usb_audio";
private static final String NAME_HDMI_AUDIO = "hdmi_audio";
+ private static final String NAME_DP_AUDIO = "soc:qcom,msm-ext-disp";
+ // within a device, a single stream supports DP
+ private static final String[] DP_AUDIO_CONNS = {
+ NAME_DP_AUDIO + "/1/0",
+ NAME_DP_AUDIO + "/0/0"
+ };
private static final String NAME_HDMI = "hdmi";
private static final int MSG_NEW_DEVICE_STATE = 1;
@@ -81,6 +87,7 @@
private final AudioManager mAudioManager;
private int mHeadsetState;
+ private int mDpCount;
private int mSwitchValues;
@@ -123,7 +130,7 @@
}
- if (ExtconUEventObserver.extconExists()) {
+ if (ExtconUEventObserver.extconExists() && mExtconObserver.uEventCount() > 0) {
if (mUseDevInputEventForAudioJack) {
Log.w(TAG, "Both input event and extcon are used for audio jack,"
+ " please just choose one.");
@@ -172,7 +179,7 @@
break;
}
- updateLocked(NAME_H2W,
+ updateLocked(NAME_H2W, "",
(mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
}
}
@@ -193,25 +200,33 @@
* results in support for the last one plugged in. Similarly, unplugging either is seen as
* unplugging all.
*
+ * For Display port allow upto two connections.
+ * Block display port request if HDMI already connected and vice versa.
+ *
* @param newName One of the NAME_xxx variables defined above.
* @param newState 0 or one of the BIT_xxx variables defined above.
*/
- private void updateLocked(String newName, int newState) {
+ private void updateLocked(String newName, String address, int newState) {
// Retain only relevant bits
int headsetState = newState & SUPPORTED_HEADSETS;
+ int newDpState = newState & BIT_HDMI_AUDIO;
int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT);
boolean h2wStateChange = true;
boolean usbStateChange = true;
+ boolean dpBitState = (mHeadsetState & BIT_HDMI_AUDIO) > 0 ? true: false;
+ boolean dpCountState = (mDpCount == 0) ? false: true;
+
if (LOG) {
Slog.v(TAG, "newName=" + newName
+ " newState=" + newState
+ " headsetState=" + headsetState
- + " prev headsetState=" + mHeadsetState);
+ + " prev headsetState=" + mHeadsetState
+ + " num of active dp conns= " + mDpCount);
}
- if (mHeadsetState == headsetState) {
+ if (mHeadsetState == headsetState && !newName.startsWith(NAME_DP_AUDIO)) {
Log.e(TAG, "No state change.");
return;
}
@@ -234,11 +249,45 @@
return;
}
+ if (newName.startsWith(NAME_DP_AUDIO)) {
+ if ((newDpState > 0) && (mDpCount < DP_AUDIO_CONNS.length)
+ && (dpBitState == dpCountState)) {
+ // Allow DP0 if no HDMI previously connected.
+ // Allow second request only if DP connected previously.
+ mDpCount++;
+ } else if ((newDpState == 0) && (mDpCount > 0)){
+ mDpCount--;
+ } else {
+ Log.e(TAG, "No state change for DP.");
+ return;
+ }
+ }
+
mWakeLock.acquire();
Log.i(TAG, "MSG_NEW_DEVICE_STATE");
- Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
- mHeadsetState, "");
+
+ Message msg;
+ // send a combined name, address string separated by |
+ if (newName.startsWith(NAME_DP_AUDIO)) {
+ int pseudoHeadsetState = mHeadsetState;
+ if (dpBitState && (newDpState != 0)) {
+ // One DP already connected, so allow request to connect second.
+ pseudoHeadsetState = mHeadsetState & (~BIT_HDMI_AUDIO);
+ }
+ msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
+ pseudoHeadsetState,
+ NAME_DP_AUDIO+"/"+address);
+
+ if ((headsetState == 0) && (mDpCount != 0)) {
+ // Atleast one DP is connected, so keep mHeadsetState's DP bit set.
+ headsetState = headsetState | BIT_HDMI_AUDIO;
+ }
+ } else {
+ msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
+ mHeadsetState,
+ newName+"/"+address);
+ }
mHandler.sendMessage(msg);
mHeadsetState = headsetState;
@@ -261,12 +310,13 @@
};
private void setDevicesState(
- int headsetState, int prevHeadsetState, String headsetName) {
+ int headsetState, int prevHeadsetState, String headsetNameAddr) {
synchronized (mLock) {
int allHeadsets = SUPPORTED_HEADSETS;
for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
if ((curHeadset & allHeadsets) != 0) {
- setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
+ setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState,
+ headsetNameAddr);
allHeadsets &= ~curHeadset;
}
}
@@ -274,7 +324,7 @@
}
private void setDeviceStateLocked(int headset,
- int headsetState, int prevHeadsetState, String headsetName) {
+ int headsetState, int prevHeadsetState, String headsetNameAddr) {
if ((headsetState & headset) != (prevHeadsetState & headset)) {
int outDevice = 0;
int inDevice = 0;
@@ -305,15 +355,23 @@
}
if (LOG) {
- Slog.v(TAG, "headsetName: " + headsetName +
- (state == 1 ? " connected" : " disconnected"));
+ Slog.v(TAG, "headset: " + headsetNameAddr +
+ (state == 1 ? " connected" : " disconnected"));
}
+ String[] hs = headsetNameAddr.split("/");
if (outDevice != 0) {
- mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
+ if (LOG) {
+ Slog.v(TAG, "Output device address " + (hs.length > 1 ? hs[1] : "")
+ + " name " + hs[0]);
+ }
+ mAudioManager.setWiredDeviceConnectionState(outDevice, state,
+ (hs.length > 1 ? hs[1] : ""), hs[0]);
}
if (inDevice != 0) {
- mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
+
+ mAudioManager.setWiredDeviceConnectionState(inDevice, state,
+ (hs.length > 1 ? hs[1] : ""), hs[0]);
}
}
}
@@ -342,7 +400,6 @@
synchronized (mLock) {
if (LOG) Slog.v(TAG, "init()");
char[] buffer = new char[1024];
-
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
try {
@@ -416,30 +473,108 @@
}
}
+ for (String conn : DP_AUDIO_CONNS) {
+ // Monitor DisplayPort
+ if (LOG) {
+ Slog.v(TAG, "Monitor DP conn " + conn);
+ }
+ uei = new UEventInfo(conn, BIT_HDMI_AUDIO, 0, 0);
+ if (uei.checkSwitchExists()) {
+ retVal.add(uei);
+ } else {
+ Slog.w(TAG, "Conn " + conn + " does not have DP audio support");
+ }
+ }
return retVal;
}
@Override
public void onUEvent(UEventObserver.UEvent event) {
- if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
+ String devPath = event.get("DEVPATH");
+ String name = event.get("NAME");
+ int state = 0;
+
+ if (name == null)
+ name = event.get("SWITCH_NAME");
try {
- String devPath = event.get("DEVPATH");
- String name = event.get("SWITCH_NAME");
- int state = Integer.parseInt(event.get("SWITCH_STATE"));
- synchronized (mLock) {
- updateStateLocked(devPath, name, state);
+ if (name.startsWith(NAME_DP_AUDIO)) {
+ String state_str = event.get("STATE");
+ int offset = 0;
+ int length = state_str.length();
+
+ //parse DP=1\nHDMI=1\0
+ while (offset < length) {
+ int equals = state_str.indexOf('=', offset);
+
+ if (equals > offset) {
+ String intf_name = state_str.substring(offset,
+ equals);
+
+ if (intf_name.equals("DP")) {
+ state = Integer.parseInt(
+ state_str.substring(equals + 1,
+ equals + 2));
+ break;
+ }
+ }
+
+ offset = equals + 3;
+ }
+ } else {
+ state = Integer.parseInt(event.get("SWITCH_STATE"));
}
} catch (NumberFormatException e) {
- Slog.e(TAG, "Could not parse switch state from event " + event);
+ Slog.i(TAG, "couldn't get state from event, checking node");
+
+ for (int i = 0; i < mUEventInfo.size(); ++i) {
+ UEventInfo uei = mUEventInfo.get(i);
+
+ if (name.equals(uei.getDevName())) {
+ char[] buffer = new char[1024];
+ int len = 0;
+
+ try {
+ FileReader file = new FileReader(
+ uei.getSwitchStatePath());
+ len = file.read(buffer, 0, 1024);
+ file.close();
+ } catch (FileNotFoundException e1) {
+ Slog.e(TAG, "file not found");
+ break;
+ } catch (Exception e11) {
+ Slog.e(TAG, "" , e11);
+ }
+
+ try {
+ state = Integer.parseInt(
+ (new String(buffer, 0, len)).trim());
+ } catch (NumberFormatException e2) {
+ Slog.e(TAG, "could not convert to number");
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ synchronized (mLock) {
+ updateStateLocked(devPath, name, state);
}
}
private void updateStateLocked(String devPath, String name, int state) {
for (int i = 0; i < mUEventInfo.size(); ++i) {
UEventInfo uei = mUEventInfo.get(i);
+ if (LOG) {
+ Slog.v(TAG, "uei.getDevPath=" + uei.getDevPath());
+ Slog.v(TAG, "uevent.getDevPath=" + devPath);
+ }
+
if (devPath.equals(uei.getDevPath())) {
- updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
+ updateLocked(name, uei.getDevAddress(),
+ uei.computeNewHeadsetState(mHeadsetState,
+ state));
return;
}
}
@@ -447,27 +582,144 @@
private final class UEventInfo {
private final String mDevName;
+ private String mDevAddress;
private final int mState1Bits;
private final int mState2Bits;
private final int mStateNbits;
+ private int mDevIndex;
+ private int mCableIndex;
- public UEventInfo(String devName, int state1Bits, int state2Bits, int stateNbits) {
+ public UEventInfo(String devName, int state1Bits,
+ int state2Bits, int stateNbits) {
mDevName = devName;
+ mDevAddress = "controller=0;stream=0";
mState1Bits = state1Bits;
mState2Bits = state2Bits;
mStateNbits = stateNbits;
+ mDevIndex = -1;
+ mCableIndex = -1;
+
+ if (mDevName.startsWith(NAME_DP_AUDIO)) {
+ int idx = mDevName.indexOf("/");
+ if (idx != -1) {
+ int idx2 = mDevName.indexOf("/", idx+1);
+ assert(idx2 != -1);
+ int dev = Integer.parseInt(mDevName.substring(idx+1, idx2));
+ int cable = Integer.parseInt(mDevName.substring(idx2+1));
+ mDevAddress = "controller=" + cable + ";stream=" + dev;
+ if (LOG) {
+ Slog.v(TAG, "UEvent dev address " + mDevAddress);
+ }
+ checkDevIndex(dev);
+ checkCableIndex(cable);
+ }
+ }
+ }
+
+ private void checkDevIndex(int dev_index) {
+ int index = 0;
+ char[] buffer = new char[1024];
+ while (true) {
+ String devPath = String.format(Locale.US,
+ "/sys/devices/platform/soc/%s/extcon/extcon%d/name",
+ NAME_DP_AUDIO, index);
+ if (LOG) {
+ Slog.v(TAG, "checkDevIndex " + devPath);
+ }
+ File f = new File(devPath);
+ if (!f.exists()) {
+ Slog.e(TAG, "file " + devPath + " not found");
+ break;
+ }
+ try {
+ FileReader file = new FileReader(f);
+ int len = file.read(buffer, 0, 1024);
+ file.close();
+
+ String devName = (new String(buffer, 0, len)).trim();
+ if (devName.startsWith(NAME_DP_AUDIO) && index == dev_index) {
+ Slog.e(TAG, "set dev_index " + dev_index);
+ mDevIndex = dev_index;
+ break;
+ } else {
+ index++;
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "checkDevIndex exception " , e);
+ break;
+ }
+ }
+ }
+
+ private void checkCableIndex(int cable_index) {
+ if (mDevIndex == -1) {
+ return;
+ }
+ int index = 0;
+ char[] buffer = new char[1024];
+ while (true)
+ {
+ String cablePath = String.format(Locale.US,
+ "/sys/devices/platform/soc/%s/extcon/extcon%d/cable.%d/name",
+ NAME_DP_AUDIO, mDevIndex, index);
+ if (LOG) {
+ Slog.v(TAG, "checkCableIndex " + cablePath);
+ }
+ File f = new File(cablePath);
+ if (!f.exists()) {
+ Slog.e(TAG, "file " + cablePath + " not found");
+ break;
+ }
+ try {
+ FileReader file = new FileReader(f);
+ int len = file.read(buffer, 0, 1024);
+ file.close();
+
+ String cableName = (new String(buffer, 0, len)).trim();
+ if (cableName.equals("DP") && index == cable_index) {
+ mCableIndex = index;
+ Slog.w(TAG, "checkCableIndex set cable " + cable_index);
+ break;
+ } else {
+ Slog.w(TAG, "checkCableIndex no name match, skip ");
+ index++;
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "checkCableIndex exception", e);
+ break;
+ }
+ }
}
public String getDevName() {
return mDevName;
}
+ public String getDevAddress() { return mDevAddress; }
+
public String getDevPath() {
- return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName);
+ if (mDevName.startsWith(NAME_DP_AUDIO)) {
+ return String.format(Locale.US,
+ "/devices/platform/soc/%s/extcon/extcon%d",
+ NAME_DP_AUDIO,
+ mDevIndex);
+ } else {
+ return String.format(Locale.US,
+ "/devices/virtual/switch/%s",
+ mDevName);
+ }
}
public String getSwitchStatePath() {
- return String.format(Locale.US, "/sys/class/switch/%s/state", mDevName);
+ if (mDevName.startsWith(NAME_DP_AUDIO)) {
+ return String.format(Locale.US,
+ "/sys/devices/platform/soc/%s/extcon/extcon%d/cable.%d/state",
+ NAME_DP_AUDIO, mDevIndex, mCableIndex);
+ } else {
+ return String.format(Locale.US,
+ "/sys/class/switch/%s/state",
+ mDevName);
+ }
}
public boolean checkSwitchExists() {
@@ -518,6 +770,10 @@
}
+ public int uEventCount() {
+ return mExtconInfos.size();
+ }
+
@Override
public Pair<Integer, Integer> parseState(ExtconInfo extconInfo, String status) {
if (LOG) Slog.v(TAG, "status " + status);
@@ -538,7 +794,7 @@
synchronized (mLock) {
int mask = maskAndState.first;
int state = maskAndState.second;
- updateLocked(name, mHeadsetState & ~(mask & ~state) | (mask & state));
+ updateLocked(name, "", mHeadsetState & ~(mask & ~state) | (mask & state));
return;
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4f54e64..8d6deef 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1450,6 +1450,7 @@
@Override
public String getPassword(Account account) {
+ android.util.SeempLog.record(14);
int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
@@ -1530,6 +1531,7 @@
@Override
public String getUserData(Account account, String key) {
+ android.util.SeempLog.record(15);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
@@ -2104,6 +2106,7 @@
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
+ android.util.SeempLog.record(17);
removeAccountAsUser(
response,
account,
@@ -2545,6 +2548,7 @@
@Override
public void setPassword(Account account, String password) {
+ android.util.SeempLog.record(18);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
@@ -2611,6 +2615,7 @@
@Override
public void clearPassword(Account account) {
+ android.util.SeempLog.record(19);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
@@ -2637,6 +2642,7 @@
@Override
public void setUserData(Account account, String key, String value) {
+ android.util.SeempLog.record(20);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
@@ -3120,6 +3126,7 @@
public void addAccount(final IAccountManagerResponse response, final String accountType,
final String authTokenType, final String[] requiredFeatures,
final boolean expectActivityLaunch, final Bundle optionsIn) {
+ android.util.SeempLog.record(16);
Bundle.setDefusable(optionsIn, true);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccount: accountType " + accountType
@@ -3873,6 +3880,7 @@
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
+ android.util.SeempLog.record(21);
final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "editProperties: accountType " + accountType
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index eb77fea..a9ad2ba 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -73,6 +73,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.BoostFramework;
import android.util.EventLog;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -95,7 +96,9 @@
import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.uri.NeededUriGrants;
+import com.android.server.wm.ActivityRecord;
import com.android.server.wm.ActivityServiceConnectionsHolder;
+import com.android.server.wm.ActivityStack;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -108,6 +111,10 @@
import java.util.Set;
import java.util.function.Predicate;
+import vendor.qti.hardware.servicetracker.V1_0.IServicetracker;
+import vendor.qti.hardware.servicetracker.V1_0.ServiceData;
+import vendor.qti.hardware.servicetracker.V1_0.ClientData;
+
public final class ActiveServices {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
private static final String TAG_MU = TAG + POSTFIX_MU;
@@ -137,6 +144,12 @@
// at the same time.
final int mMaxStartingBackground;
+ //mPerf Object
+ public static BoostFramework mPerf = new BoostFramework();
+
+ // Flag to reschedule the services during app launch. Disable by default.
+ private static boolean SERVICE_RESCHEDULE = false;
+
final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();
/**
@@ -174,6 +187,8 @@
/** Amount of time to allow a last ANR message to exist before freeing the memory. */
static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
+ private IServicetracker mServicetracker;
+
String mLastAnrDump;
final Runnable mLastAnrDumpClearer = new Runnable() {
@@ -364,6 +379,9 @@
}
mMaxStartingBackground = maxBg > 0
? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
+
+ if(mPerf != null)
+ SERVICE_RESCHEDULE = Boolean.parseBoolean(mPerf.perfGetProp("ro.vendor.qti.am.reschedule_service", "false"));
}
void systemServicesReady() {
@@ -371,6 +389,24 @@
ast.addListener(new ForcedStandbyListener());
}
+ private boolean getServicetrackerInstance() {
+ if (mServicetracker == null ) {
+ try {
+ mServicetracker = IServicetracker.getService(false);
+ } catch (java.util.NoSuchElementException e) {
+ // Service doesn't exist or cannot be opened logged below
+ } catch (RemoteException e) {
+ if (DEBUG_SERVICE) Slog.e(TAG, "Failed to get servicetracker interface", e);
+ return false;
+ }
+ if (mServicetracker == null) {
+ if (DEBUG_SERVICE) Slog.w(TAG, "servicetracker HIDL not available");
+ return false;
+ }
+ }
+ return true;
+ }
+
ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {
// TODO: Deal with global services
if (DEBUG_MU)
@@ -1800,6 +1836,30 @@
}
clist.add(c);
+ ServiceData sData = new ServiceData();
+ sData.packageName = s.packageName;
+ sData.processName = s.shortInstanceName;
+ sData.lastActivity = s.lastActivity;
+ if (s.app != null) {
+ sData.pid = s.app.pid;
+ sData.serviceB = s.app.serviceb;
+ } else {
+ sData.pid = -1;
+ sData.serviceB = false;
+ }
+
+ ClientData cData = new ClientData();
+ cData.processName = callerApp.processName;
+ cData.pid = callerApp.pid;
+ try {
+ if (getServicetrackerInstance()) {
+ mServicetracker.bindService(sData, cData);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send bind details to servicetracker HAL", e);
+ mServicetracker = null;
+ }
+
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
@@ -1954,6 +2014,29 @@
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
+ ServiceData sData = new ServiceData();
+ sData.packageName = r.binding.service.packageName;
+ sData.processName = r.binding.service.shortInstanceName;
+ sData.lastActivity = r.binding.service.lastActivity;
+ if(r.binding.service.app != null) {
+ sData.pid = r.binding.service.app.pid;
+ sData.serviceB = r.binding.service.app.serviceb;
+ } else {
+ sData.pid = -1;
+ sData.serviceB = false;
+ }
+
+ ClientData cData = new ClientData();
+ cData.processName = r.binding.client.processName;
+ cData.pid = r.binding.client.pid;
+ try {
+ if (getServicetrackerInstance()) {
+ mServicetracker.unbindService(sData, cData);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send unbind details to servicetracker HAL", e);
+ mServicetracker = null;
+ }
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
@@ -2383,6 +2466,14 @@
r.pendingStarts.add(0, si);
long dur = SystemClock.uptimeMillis() - si.deliveredTime;
dur *= 2;
+ if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
+ Slog.w(TAG,"Can add more delay !!!"
+ +" si.deliveredTime "+si.deliveredTime
+ +" dur "+dur
+ +" si.deliveryCount "+si.deliveryCount
+ +" si.doneExecutingCount "+si.doneExecutingCount
+ +" allowCancel "+allowCancel);
+ }
if (minDuration < dur) minDuration = dur;
if (resetTime < dur) resetTime = dur;
} else {
@@ -2406,6 +2497,13 @@
}
r.totalRestartCount++;
+ if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
+ Slog.w(TAG,"r.name "+r.name+" N "+N+" minDuration "+minDuration
+ +" resetTime "+resetTime+" now "+now
+ +" r.restartDelay "+r.restartDelay
+ +" r.restartTime+resetTime "+(r.restartTime+resetTime)
+ +" allowCancel "+allowCancel);
+ }
if (r.restartDelay == 0) {
r.restartCount++;
r.restartDelay = minDuration;
@@ -2430,6 +2528,14 @@
}
r.nextRestartTime = now + r.restartDelay;
+ if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
+ Slog.w(TAG,"r.name "+r.name+" N "+N+" minDuration "+minDuration
+ +" resetTime "+resetTime+" now "+now
+ +" r.restartDelay "+r.restartDelay
+ +" r.restartTime+resetTime "+(r.restartTime+resetTime)
+ +" r.nextRestartTime "+r.nextRestartTime
+ +" allowCancel "+allowCancel);
+ }
// Make sure that we don't end up restarting a bunch of services
// all at the same time.
@@ -2472,6 +2578,15 @@
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
Slog.w(TAG, "Scheduling restart of crashed service "
+ r.shortInstanceName + " in " + r.restartDelay + "ms for " + reason);
+
+ if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
+ for (int i=mRestartingServices.size()-1; i>=0; i--) {
+ ServiceRecord r2 = mRestartingServices.get(i);
+ Slog.w(TAG,"Restarting list - i "+i+" r2.nextRestartTime "
+ +r2.nextRestartTime+" r2.name "+r2.name);
+ }
+ }
+
EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
r.userId, r.shortInstanceName, r.restartDelay);
@@ -2492,7 +2607,35 @@
return;
}
try {
- bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
+ if(SERVICE_RESCHEDULE) {
+ boolean shouldDelay = false;
+ ActivityRecord top_rc = null;
+ ActivityStack stack = mAm.mStackSupervisor.mRootActivityContainer.getTopDisplayFocusedStack();
+ if(stack != null) {
+ top_rc = stack.topRunningActivityLocked();
+ }
+
+ boolean isPersistent
+ = !((r.serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0);
+ if(top_rc != null) {
+ if(top_rc.launching && !r.shortInstanceName.contains(top_rc.packageName)
+ && !isPersistent) {
+ shouldDelay = true;
+ }
+ }
+ if(!shouldDelay) {
+ bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
+ } else {
+ if (DEBUG_DELAYED_SERVICE) {
+ Slog.v(TAG, "Reschedule service restart due to app launch"
+ +" r.shortInstanceName "+r.shortInstanceName+" r.app = "+r.app);
+ }
+ r.resetRestartCounter();
+ scheduleServiceRestartLocked(r, true);
+ }
+ } else {
+ bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
+ }
} catch (TransactionTooLargeException e) {
// Ignore, it's been logged and nothing upstack cares.
}
@@ -2728,6 +2871,22 @@
app.getReportedProcState());
r.postNotification();
created = true;
+
+ ServiceData sData = new ServiceData();
+ sData.packageName = r.packageName;
+ sData.processName = r.shortInstanceName;
+ sData.pid = r.app.pid;
+ sData.lastActivity = r.lastActivity;
+ sData.serviceB = r.app.serviceb;
+
+ try {
+ if (getServicetrackerInstance()) {
+ mServicetracker.startService(sData);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send start details to servicetracker HAL", e);
+ mServicetracker = null;
+ }
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
@@ -2741,7 +2900,12 @@
// Cleanup.
if (newService) {
app.services.remove(r);
- r.setProcess(null);
+ r.app = null;
+ if (SERVICE_RESCHEDULE && DEBUG_DELAYED_SERVICE) {
+ Slog.w(TAG, " Failed to create Service !!!! ."
+ +"This will introduce huge delay... "
+ +r.shortInstanceName + " in " + r.restartDelay + "ms");
+ }
}
// Retry.
@@ -2920,7 +3084,25 @@
private final void bringDownServiceLocked(ServiceRecord r) {
//Slog.i(TAG, "Bring down service:");
//r.dump(" ");
+ ServiceData sData = new ServiceData();
+ sData.packageName = r.packageName;
+ sData.processName = r.shortInstanceName;
+ sData.lastActivity = r.lastActivity;
+ if (r.app != null) {
+ sData.pid = r.app.pid;
+ } else {
+ sData.pid = -1;
+ sData.serviceB = false;
+ }
+ try {
+ if (getServicetrackerInstance()) {
+ mServicetracker.destroyService(sData);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send destroy details to servicetracker HAL", e);
+ mServicetracker = null;
+ }
// Report to all of the connections that the service is no longer
// available.
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
@@ -3581,6 +3763,15 @@
}
}
+ try {
+ if (getServicetrackerInstance()) {
+ mServicetracker.killProcess(app.pid);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to send kill process details to servicetracker HAL", e);
+ mServicetracker = null;
+ }
+
// Clean up any connections this application has to other services.
for (int i = app.connections.size() - 1; i >= 0; i--) {
ConnectionRecord r = app.connections.valueAt(i);
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 9085d18..1bf715e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -25,11 +25,14 @@
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
+import android.os.SystemProperties;
+import android.os.Process;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.BoostFramework;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -78,7 +81,7 @@
static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
- private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+ private static int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
@@ -271,6 +274,15 @@
// process limit.
public int CUR_MAX_CACHED_PROCESSES;
+ public static BoostFramework mPerf = new BoostFramework();
+
+ static boolean USE_TRIM_SETTINGS = true;
+ static int EMPTY_APP_PERCENT = 50;
+ static int TRIM_EMPTY_PERCENT = 100;
+ static int TRIM_CACHE_PERCENT = 100;
+ static long TRIM_ENABLE_MEMORY = 1073741824;
+ public static boolean allowTrim() { return Process.getTotalMemory() < TRIM_ENABLE_MEMORY ; }
+
// The maximum number of empty app processes we will let sit around.
public int CUR_MAX_EMPTY_PROCESSES;
@@ -350,6 +362,19 @@
MIN_AUTOMATIC_HEAP_DUMP_PSS_THRESHOLD_BYTES,
context.getResources().getInteger(
com.android.internal.R.integer.config_debugSystemServerPssThresholdBytes));
+
+ if (mPerf != null) {
+ // Maximum number of cached processes we will allow.
+ DEFAULT_MAX_CACHED_PROCESSES = MAX_CACHED_PROCESSES = Integer.valueOf(
+ mPerf.perfGetProp("ro.vendor.qti.sys.fw.bg_apps_limit", "32"));
+
+ //Trim Settings
+ USE_TRIM_SETTINGS = Boolean.parseBoolean(mPerf.perfGetProp("ro.vendor.qti.sys.fw.use_trim_settings", "true"));
+ EMPTY_APP_PERCENT = Integer.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.empty_app_percent", "50"));
+ TRIM_EMPTY_PERCENT = Integer.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.trim_empty_percent", "100"));
+ TRIM_CACHE_PERCENT = Integer.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.trim_cache_percent", "100"));
+ TRIM_ENABLE_MEMORY = Long.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.trim_enable_memory", "1073741824"));
+ }
}
public void start(ContentResolver resolver) {
@@ -383,7 +408,27 @@
}
public static int computeEmptyProcessLimit(int totalProcessLimit) {
- return totalProcessLimit/2;
+ if(USE_TRIM_SETTINGS && allowTrim()) {
+ return totalProcessLimit*EMPTY_APP_PERCENT/100;
+ } else {
+ return totalProcessLimit/2;
+ }
+ }
+
+ public static int computeTrimEmptyApps(int rawMaxEmptyProcesses) {
+ if (USE_TRIM_SETTINGS && allowTrim()) {
+ return rawMaxEmptyProcesses*TRIM_EMPTY_PERCENT/100;
+ } else {
+ return rawMaxEmptyProcesses/2;
+ }
+ }
+
+ public static int computeTrimCachedApps(int rawMaxEmptyProcesses, int totalProcessLimit) {
+ if (USE_TRIM_SETTINGS && allowTrim()) {
+ return totalProcessLimit*TRIM_CACHE_PERCENT/100;
+ } else {
+ return (totalProcessLimit-rawMaxEmptyProcesses)/3;
+ }
}
@Override
@@ -535,8 +580,9 @@
// to consider the same level the point where we do trimming regardless of any
// additional enforced limit.
final int rawMaxEmptyProcesses = computeEmptyProcessLimit(MAX_CACHED_PROCESSES);
- CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses/2;
- CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3;
+ CUR_TRIM_EMPTY_PROCESSES = computeTrimEmptyApps(rawMaxEmptyProcesses);
+ CUR_TRIM_CACHED_PROCESSES =
+ computeTrimCachedApps(rawMaxEmptyProcesses, MAX_CACHED_PROCESSES);
}
void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 11cfe12..e50d028 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -74,6 +74,8 @@
import static android.os.Process.readProcFile;
import static android.os.Process.removeAllProcessGroups;
import static android.os.Process.sendSignal;
+import static android.os.Process.setProcessGroup;
+import static android.os.Process.setCgroupProcsProcessGroup;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
@@ -297,6 +299,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import android.util.BoostFramework;
+
import android.view.autofill.AutofillManagerInternal;
import com.android.internal.R;
@@ -308,6 +312,7 @@
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.app.ActivityTrigger;
import com.android.internal.content.PackageHelper;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -361,6 +366,7 @@
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.ActivityMetricsLaunchObserver;
import com.android.server.wm.ActivityServiceConnectionsHolder;
+import com.android.server.wm.ActivityStackSupervisor;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowManagerService;
@@ -534,6 +540,12 @@
private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes.
+ /* Freq Aggr boost objects */
+ public static BoostFramework mPerfServiceStartHint = null;
+ /* UX perf event object */
+ public static BoostFramework mUxPerf = new BoostFramework();
+ public static boolean mForceStopKill = false;
+
OomAdjuster mOomAdjuster;
final LowMemDetector mLowMemDetector;
@@ -546,6 +558,9 @@
private Installer mInstaller;
+ /** Run all ActivityStacks through this */
+ ActivityStackSupervisor mStackSupervisor;
+
final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
final ArrayList<ActiveInstrumentation> mActiveInstrumentation = new ArrayList<>();
@@ -1535,6 +1550,8 @@
static final String SERVICE_RECORD_KEY = "servicerecord";
+ static final ActivityTrigger mActivityTrigger = new ActivityTrigger();
+
long mLastMemUsageReportTime = 0;
/**
@@ -2509,6 +2526,7 @@
mActivityTaskManager.initialize(mIntentFirewall, mPendingIntentController,
DisplayThread.get().getLooper());
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mStackSupervisor = mActivityTaskManager.mStackSupervisor;
mProcessCpuThread = new Thread("CpuTracker") {
@Override
@@ -3507,6 +3525,46 @@
return mActivityTaskManager.startActivityFromRecents(taskId, bOptions);
}
+ public int startActivityAsUserEmpty(Bundle options) {
+ ArrayList<String> pApps = options.getStringArrayList("start_empty_apps");
+ if (pApps != null && pApps.size() > 0) {
+ Iterator<String> apps_itr = pApps.iterator();
+ while (apps_itr.hasNext()) {
+ ProcessRecord empty_app = null;
+ String app_str = apps_itr.next();
+ if (app_str == null)
+ continue;
+ synchronized (this) {
+ Intent intent_l = null;
+ try {
+ intent_l = mContext.getPackageManager().getLaunchIntentForPackage(app_str);
+ if (intent_l == null)
+ continue;
+ ActivityInfo aInfo = mStackSupervisor.resolveActivity(intent_l, null,
+ 0, null, 0, 0);
+ if (aInfo == null)
+ continue;
+ empty_app = startProcessLocked(
+ app_str,
+ aInfo.applicationInfo,
+ false /* knownToBeDead */,
+ 0 /* intentFlags */,
+ sNullHostingRecord /* hostingRecord */,
+ false /* allowWhileBooting */,
+ false /* isolated */,
+ true /* keepIfLarge */);
+ if (empty_app != null)
+ updateOomAdjLocked(empty_app, true, OomAdjuster.OOM_ADJ_REASON_NONE);
+ } catch (Exception e) {
+ if (DEBUG_PROCESSES)
+ Slog.w(TAG, "Exception raised trying to start app as empty " + e);
+ }
+ }
+ }
+ }
+ return 1;
+ }
+
@Override
public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
IRecentsAnimationRunner recentsAnimationRunner) {
@@ -3730,6 +3788,12 @@
mAllowLowerMemLevel = false;
doLowMem = false;
}
+
+ if (mUxPerf != null && !mForceStopKill) {
+ mUxPerf.perfUXEngine_events(BoostFramework.UXE_EVENT_KILL, 0, app.processName, 0);
+ mUxPerf.perfHint(BoostFramework.VENDOR_HINT_KILL, app.processName, pid, 0);
+ }
+
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
app.setAdj, app.setProcState);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
@@ -4628,9 +4692,13 @@
} else {
Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
}
+ if (mUxPerf != null) {
+ mUxPerf.perfHint(BoostFramework.VENDOR_HINT_KILL, packageName, appId, 0);
+ }
mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId);
}
+ mForceStopKill = true;
boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit,
@@ -5165,6 +5233,9 @@
(int) (SystemClock.elapsedRealtime() - app.startTime),
app.hostingRecord.getType(),
(app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""));
+
+ //send start notification to AT with the starting app's info.
+ mActivityTrigger.activityStartTrigger(app.info, app.pid);
return true;
}
@@ -17994,6 +18065,11 @@
}
@Override
+ public int startActivityAsUserEmpty(Bundle options) {
+ return ActivityManagerService.this.startActivityAsUserEmpty(options);
+ }
+
+ @Override
public void killForegroundAppsForUser(@UserIdInt int userId) {
synchronized (ActivityManagerService.this) {
final ArrayList<ProcessRecord> procs = new ArrayList<>();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 78a9efc..9d27468 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -72,10 +72,12 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.BoostFramework;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -166,6 +168,15 @@
private final ActivityManagerService mService;
private final ProcessList mProcessList;
+ // Min aging threshold in milliseconds to consider a B-service
+ int mMinBServiceAgingTime = 5000;
+ // Threshold for B-services when in memory pressure
+ int mBServiceAppThreshold = 5;
+ // Enable B-service aging propagation on memory pressure.
+ boolean mEnableBServicePropagation = false;
+
+ public static BoostFramework mPerf = new BoostFramework();
+
private final int mNumSlots;
private ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
private ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
@@ -196,6 +207,12 @@
mConstants = mService.mConstants;
mAppCompact = new AppCompactor(mService);
+ if(mPerf != null) {
+ mMinBServiceAgingTime = Integer.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.bservice_age", "5000"));
+ mBServiceAppThreshold = Integer.valueOf(mPerf.perfGetProp("ro.vendor.qti.sys.fw.bservice_limit", "5"));
+ mEnableBServicePropagation = Boolean.parseBoolean(mPerf.perfGetProp("ro.vendor.qti.sys.fw.bservice_enable", "false"));
+ }
+
mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
final int pid = msg.arg1;
final int group = msg.arg2;
@@ -701,9 +718,40 @@
int numCachedExtraGroup = 0;
int numEmpty = 0;
int numTrimming = 0;
+ ProcessRecord selectedAppRecord = null;
+ long serviceLastActivity = 0;
+ int numBServices = 0;
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
+ if (mEnableBServicePropagation && app.serviceb
+ && (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
+ numBServices++;
+ for (int s = app.services.size() - 1; s >= 0; s--) {
+ ServiceRecord sr = app.services.valueAt(s);
+ if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + app.processName
+ + " serviceb = " + app.serviceb + " s = " + s + " sr.lastActivity = "
+ + sr.lastActivity + " packageName = " + sr.packageName
+ + " processName = " + sr.processName);
+ if (SystemClock.uptimeMillis() - sr.lastActivity
+ < mMinBServiceAgingTime) {
+ if (DEBUG_OOM_ADJ) {
+ Slog.d(TAG,"Not aged enough!!!");
+ }
+ continue;
+ }
+ if (serviceLastActivity == 0) {
+ serviceLastActivity = sr.lastActivity;
+ selectedAppRecord = app;
+ } else if (sr.lastActivity < serviceLastActivity) {
+ serviceLastActivity = sr.lastActivity;
+ selectedAppRecord = app;
+ }
+ }
+ }
+ if (DEBUG_OOM_ADJ && selectedAppRecord != null) Slog.d(TAG,
+ "Identified app.processName = " + selectedAppRecord.processName
+ + " app.pid = " + selectedAppRecord.pid);
if (!app.killedByAm && app.thread != null) {
// We don't need to apply the update for the process which didn't get computed
if (app.completedAdjSeq == mAdjSeq) {
@@ -773,6 +821,15 @@
}
}
+ if ((numBServices > mBServiceAppThreshold) && (true == mService.mAllowLowerMemLevel)
+ && (selectedAppRecord != null)) {
+ ProcessList.setOomAdj(selectedAppRecord.pid, selectedAppRecord.info.uid,
+ ProcessList.CACHED_APP_MAX_ADJ);
+ selectedAppRecord.setAdj = selectedAppRecord.curAdj;
+ if (DEBUG_OOM_ADJ) Slog.d(TAG,"app.processName = " + selectedAppRecord.processName
+ + " app.pid = " + selectedAppRecord.pid + " is moved to higher adj");
+ }
+
mProcessList.incrementProcStateSeqAndNotifyAppsLocked(activeUids);
return mService.updateLowMemStateLocked(numCached, numEmpty, numTrimming);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 8163a6d..c8f447f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -86,6 +86,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.StatsLog;
+import android.util.BoostFramework;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
@@ -392,6 +393,10 @@
final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+ /**
+ * BoostFramework Object
+ */
+ public static BoostFramework mPerfServiceStartHint = new BoostFramework();
final class IsolatedUidRange {
@VisibleForTesting
public final int mFirstUid;
@@ -1837,6 +1842,13 @@
app.info.dataDir, invokeWith, app.info.packageName, isTopApp,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
+ if (mPerfServiceStartHint != null) {
+ if ((hostingRecord.getType() != null) && (hostingRecord.getType().equals("activity"))) {
+ if (startResult != null) {
+ mPerfServiceStartHint.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, app.processName, startResult.pid, BoostFramework.Launch.TYPE_START_PROC);
+ }
+ }
+ }
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bf43f3b..b181a7f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -55,6 +55,7 @@
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.util.BoostFramework;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessState;
@@ -62,6 +63,7 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.Zygote;
+import com.android.server.Watchdog;
import com.android.server.wm.WindowProcessController;
import com.android.server.wm.WindowProcessListener;
@@ -617,6 +619,18 @@
}
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
+ String seempStr = "app_uid=" + uid
+ + ",app_pid=" + pid + ",oom_adj=" + curAdj
+ + ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ + ",cached=" + (cached ? 1 : 0)
+ + ",fA=" + (mHasForegroundActivities ? 1 : 0)
+ + ",fS=" + (mHasForegroundServices ? 1 : 0)
+ + ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ + ",curSchedGroup=" + mCurSchedGroup
+ + ",curProcState=" + getCurProcState() + ",setProcState=" + setProcState
+ + ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ + ",isDebugging=" + (isDebugging() ? 1 : 0);
+ android.util.SeempLog.record_str(386, seempStr);
if (thread == null) {
final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
@@ -650,6 +664,18 @@
}
public void makeInactive(ProcessStatsService tracker) {
+ String seempStr = "app_uid=" + uid
+ + ",app_pid=" + pid + ",oom_adj=" + curAdj
+ + ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ + ",cached=" + (cached ? 1 : 0)
+ + ",fA=" + (mHasForegroundActivities ? 1 : 0)
+ + ",fS=" + (mHasForegroundServices ? 1 : 0)
+ + ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ + ",curSchedGroup=" + mCurSchedGroup
+ + ",curProcState=" + getCurProcState() + ",setProcState=" + setProcState
+ + ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ + ",isDebugging=" + (isDebugging() ? 1 : 0);
+ android.util.SeempLog.record_str(387, seempStr);
thread = null;
mWindowProcessController.setThread(null);
final ProcessState origBase = baseProcessTracker;
@@ -776,6 +802,7 @@
void kill(String reason, boolean noisy) {
if (!killedByAm) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
+ BoostFramework ux_perf = new BoostFramework();
if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {
mService.reportUidInfoMessageLocked(TAG,
"Killing " + toShortString() + " (adj " + setAdj + "): " + reason,
@@ -792,6 +819,12 @@
killed = true;
killedByAm = true;
}
+ if (ux_perf != null && !mService.mForceStopKill) {
+ ux_perf.perfUXEngine_events(BoostFramework.UXE_EVENT_KILL, 0, this.processName, 0);
+ ux_perf.perfHint(BoostFramework.VENDOR_HINT_KILL, this.processName, pid, 0);
+ } else {
+ mService.mForceStopKill = false;
+ }
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
@@ -1512,28 +1545,26 @@
}
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
+ ArrayList<Integer> nativePids = null;
// don't dump native PIDs for background ANRs unless it is the process of interest
- String[] nativeProcs = null;
+ String[] nativeProc = null;
if (isSilentAnr()) {
for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) {
- nativeProcs = new String[] { processName };
+ nativeProc = new String[] { processName };
break;
}
}
- } else {
- nativeProcs = NATIVE_STACKS_OF_INTEREST;
- }
-
- int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
- ArrayList<Integer> nativePids = null;
-
- if (pids != null) {
- nativePids = new ArrayList<>(pids.length);
- for (int i : pids) {
- nativePids.add(i);
+ int[] pid = nativeProc == null ? null : Process.getPidsForCommands(nativeProc);
+ if(pid != null){
+ nativePids = new ArrayList<>(pid.length);
+ for (int i : pid) {
+ nativePids.add(i);
+ }
}
+ } else {
+ nativePids = Watchdog.getInstance().getInterestingNativePids();
}
// For background ANRs, don't pass the ProcessCpuTracker to
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6010b1dc..f3717bb 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -208,6 +208,9 @@
}
mForcedUseForCommExt = mForcedUseForComm;
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In setSpeakerphoneOn(), mForcedUseForCommExt: " + mForcedUseForCommExt);
+ }
setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
return (wasOn != isSpeakerphoneOn());
}
@@ -215,6 +218,9 @@
/*package*/ boolean isSpeakerphoneOn() {
synchronized (mDeviceStateLock) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In isSpeakerphoneOn(), mForcedUseForCommExt: " +mForcedUseForCommExt);
+ }
return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
}
}
@@ -282,6 +288,15 @@
device);
}
+ /*package*/ void postBluetoothA2dpDeviceConfigChangeExt(
+ @NonNull BluetoothDevice device,
+ @AudioService.BtProfileConnectionState int state, int profile,
+ boolean suppressNoisyIntent, int a2dpVolume) {
+ final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
+ suppressNoisyIntent, a2dpVolume);
+ sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, info);
+ }
+
private static final class HearingAidDeviceConnectionInfo {
final @NonNull BluetoothDevice mDevice;
final @AudioService.BtProfileConnectionState int mState;
@@ -311,30 +326,49 @@
// never called by system components
/*package*/ void setBluetoothScoOnByApp(boolean on) {
synchronized (mDeviceStateLock) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In setBluetoothScoOnByApp(), mForcedUseForCommExt: " +
+ mForcedUseForCommExt);
+ }
mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
}
}
/*package*/ boolean isBluetoothScoOnForApp() {
synchronized (mDeviceStateLock) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In isBluetoothScoOnForApp(), mForcedUseForCommExt: " +
+ mForcedUseForCommExt);
+ }
return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO;
}
}
/*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "setBluetoothScoOn: " + on + " " + eventSource);
+ }
//Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
synchronized (mDeviceStateLock) {
if (on) {
// do not accept SCO ON if SCO audio is not connected
if (!mBtHelper.isBluetoothScoOn()) {
- mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
- return;
+ if (mBtHelper.isBluetoothAudioNotConnectedToEarbud()) {
+ Log.w(TAG, "setBluetoothScoOn(true) failed because device "+
+ "is not in audio connected mode");
+ mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
+ return;
+ }
}
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
mForcedUseForCommExt = mForcedUseForComm;
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In setbluetoothScoOn(), mForcedUseForCommExt: " +
+ mForcedUseForCommExt);
+ }
AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE,
AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
@@ -407,6 +441,10 @@
mAudioService.postAccessoryPlugMediaUnmute(device);
}
+ /*package*/ void postAccessoryPlugMediaMute(int device) {
+ mAudioService.postAccessoryPlugMediaMute(device);
+ }
+
/*package*/ int getVssVolumeForDevice(int streamType, int device) {
return mAudioService.getVssVolumeForDevice(streamType, device);
}
@@ -890,6 +928,22 @@
info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
}
} break;
+ case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT: {
+ final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
+ AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "handleBluetoothA2dpActiveDeviceChangeExt "
+ + " state=" + info.mState
+ // only querying address as this is the only readily available
+ // field on the device
+ + " addr=" + info.mDevice.getAddress()
+ + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
+ + " vol=" + info.mVolume)).printLog(TAG));
+ synchronized (mDeviceStateLock) {
+ mDeviceInventory.handleBluetoothA2dpActiveDeviceChangeExt(
+ info.mDevice, info.mState, info.mProfile,
+ info.mSupprNoisy, info.mVolume);
+ }
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -939,8 +993,10 @@
private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
// process external command to (dis)connect a hearing aid device
private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
+ // process external command to (dis)connect or change active A2DP device
+ private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT = 32;
// a ScoClient died in BtHelper
- private static final int MSG_L_SCOCLIENT_DIED = 32;
+ private static final int MSG_L_SCOCLIENT_DIED = 33;
private static boolean isMessageHandledUnderWakelock(int msgId) {
@@ -957,6 +1013,7 @@
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
+ case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT:
return true;
default:
return false;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 90973a8..ee06353 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -34,6 +34,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -319,8 +320,15 @@
return;
}
+ boolean wasMuted = false;
+
if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
// Device is connected
+
+ Log.i(TAG, "Mute the stream before reconfigure");
+ mDeviceBroker.postAccessoryPlugMediaMute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ wasMuted = true;
+
if (a2dpVolume != -1) {
mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
// convert index to internal representation in VolumeStreamState
@@ -344,6 +352,11 @@
false /* suppressNoisyIntent */, musicDevice,
-1 /* a2dpVolume */);
}
+
+ if (wasMuted && event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
+ Log.i(TAG, "Unmute the stream after reconfigure");
+ mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ }
}
}
@@ -604,6 +617,55 @@
}
}
+ /*package*/ void handleBluetoothA2dpActiveDeviceChangeExt(
+ @NonNull BluetoothDevice device,
+ @AudioService.BtProfileConnectionState int state, int profile,
+ boolean suppressNoisyIntent, int a2dpVolume) {
+ if (state == BluetoothProfile.STATE_DISCONNECTED) {
+ mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ device, state, profile, suppressNoisyIntent, a2dpVolume);
+ return;
+ }
+ // state == BluetoothProfile.STATE_CONNECTED
+ synchronized (mConnectedDevices) {
+ final String address = device.getAddress();
+ final int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
+ final String deviceKey = DeviceInfo.makeDeviceListKey(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+ DeviceInfo deviceInfo = mConnectedDevices.get(deviceKey);
+ if (deviceInfo != null) {
+ // Device config change for matching A2DP device
+ mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
+ return;
+ }
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ deviceInfo = mConnectedDevices.valueAt(i);
+ if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+ continue;
+ }
+ // A2DP device exists, handle active device change
+ final String existingDevicekey = mConnectedDevices.keyAt(i);
+ mConnectedDevices.remove(existingDevicekey);
+ mConnectedDevices.put(deviceKey, new DeviceInfo(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, BtHelper.getName(device),
+ address, a2dpCodec));
+ if (BtHelper.isTwsPlusSwitch(device, deviceInfo.mDeviceAddress)) {
+ if (AudioService.DEBUG_DEVICES) {
+ Log.d(TAG,"TWS+ device switch");
+ }
+ return;
+ }
+ mDeviceBroker.postA2dpActiveDeviceChange(
+ new BtHelper.BluetoothA2dpDeviceInfo(
+ device, a2dpVolume, a2dpCodec));
+ return;
+ }
+ }
+ // New A2DP device connection
+ mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ device, state, profile, suppressNoisyIntent, a2dpVolume);
+ }
+
/*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
String address, String name, String caller) {
synchronized (mConnectedDevices) {
@@ -642,10 +704,14 @@
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
mDeviceBroker.setBluetoothA2dpOnInt(true, eventSource);
- AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
- // Reset A2DP suspend state each time a new sink is connected
- AudioSystem.setParameters("A2dpSuspended=false");
+ final int res = AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ Slog.e(TAG, "not connecting device 0x"
+ + Integer.toHexString(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)
+ + " due to command error " + res);
+ return;
+ }
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
@@ -812,7 +878,7 @@
return 0;
}
mDeviceBroker.postBroadcastBecomingNoisy();
- delay = AudioService.BECOMING_NOISY_DELAY_MS;
+ delay = SystemProperties.getInt("audio.sys.noisy.broadcast.delay", 700);
}
return delay;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0d493b8..13b8856 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -185,6 +185,9 @@
/** debug calls to devices APIs */
protected static final boolean DEBUG_DEVICES = false;
+ /** debug SCO modes */
+ protected static final boolean DEBUG_SCO = true;
+
/** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 500;
@@ -265,6 +268,7 @@
private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
private static final int MSG_HDMI_VOLUME_CHECK = 28;
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
+ private static final int MSG_ACCESSORY_PLUG_MEDIA_MUTE = 30;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1631,6 +1635,10 @@
}
final int streamType;
synchronized (mForceControlStreamLock) {
+ if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
+ + ", flags=" + flags + ", caller=" + caller
+ + ", volControlStream=" + mVolumeControlStream
+ + ", userSelect=" + mUserSelectedVolumeControlStream);
// Request lock in case mVolumeControlStream is changed by other thread.
if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
streamType = mVolumeControlStream;
@@ -1692,11 +1700,19 @@
protected void adjustStreamVolume(int streamType, int direction, int flags,
String callingPackage, String caller, int uid) {
+ if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
+ + ", flags=" + flags + ", caller=" + caller);
+
+ /* If MirrorLink audio is playing, then disable volume changes */
+ String value = SystemProperties.get("vendor.mls.audio.session.status", "default");
+ if (true == value.equals("started")){
+ Log.e(TAG, "adjustStreamVolume() Ignore volume change during MirrorLink session");
+ return;
+ }
+
if (mUseFixedVolume) {
return;
}
- if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
- + ", flags=" + flags + ", caller=" + caller);
ensureValidDirection(direction);
ensureValidStreamType(streamType);
@@ -2284,6 +2300,14 @@
Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
+ ", calling=" + callingPackage + ")");
}
+
+ /* If MirrorLink audio is playing, then disable volume changes */
+ String value = SystemProperties.get("vendor.mls.audio.session.status", "default");
+ if (true == value.equals("started")){
+ Log.e(TAG, "setStreamVolume() Ignore volume change during MirrorLink session");
+ return;
+ }
+
if (mUseFixedVolume) {
return;
}
@@ -3229,6 +3253,7 @@
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
+ Log.i(TAG, "In binderDied(), calling disconnectBluetoothSco()");
mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid);
}
}
@@ -3252,6 +3277,8 @@
/** @see AudioManager#setMode(int) */
public void setMode(int mode, IBinder cb, String callingPackage) {
+ Log.i(TAG, "setMode(mode = " + mode + ", callingPackage = " +
+ callingPackage + ", Process ID: " + Binder.getCallingPid());
if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
if (!checkAudioSettingsPermission("setMode()")) {
return;
@@ -3545,6 +3572,8 @@
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).toString();
+ Log.i(TAG, "In setSpeakerphoneOn(), on: " + on + ", eventSource: " + eventSource);
+
final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
if (stateChanged) {
final long ident = Binder.clearCallingIdentity();
@@ -3568,9 +3597,11 @@
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
-
// Only enable calls from system components
if (UserHandle.getCallingAppId() >= FIRST_APPLICATION_UID) {
+ Log.i(TAG, "In setBluetoothScoOn(), on: "+on+". The calling application Uid: "
+ + Binder.getCallingUid() + ", is greater than FIRST_APPLICATION_UID"
+ + " exiting from setBluetoothScoOn()");
mDeviceBroker.setBluetoothScoOnByApp(on);
return;
}
@@ -3579,7 +3610,7 @@
final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).toString();
-
+ Log.i(TAG, "In setBluetoothScoOn(), eventSource: " + eventSource);
mDeviceBroker.setBluetoothScoOn(on, eventSource);
}
@@ -3607,6 +3638,12 @@
/** @see AudioManager#startBluetoothSco() */
public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+ Log.i(TAG, "In startBluetoothSco()");
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if ((adapter == null) || (adapter.getState() != BluetoothAdapter.STATE_ON)) {
+ Log.i(TAG, "startBluetoothSco(), BT is not turned ON or adapter is null");
+ return;
+ }
final int scoAudioMode =
(targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
BtHelper.SCO_MODE_VIRTUAL_CALL : BtHelper.SCO_MODE_UNDEFINED;
@@ -3618,6 +3655,7 @@
/** @see AudioManager#startBluetoothScoVirtualCall() */
public void startBluetoothScoVirtualCall(IBinder cb) {
+ Log.i(TAG, "In startBluetoothScoVirtualCall()");
final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()")
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).toString();
@@ -3625,6 +3663,7 @@
}
void startBluetoothScoInt(IBinder cb, int scoAudioMode, @NonNull String eventSource) {
+ Log.i(TAG, "In startBluetoothScoInt(), scoAudioMode: " + scoAudioMode);
if (!checkAudioSettingsPermission("startBluetoothSco()") ||
!mSystemReady) {
return;
@@ -3636,6 +3675,12 @@
/** @see AudioManager#stopBluetoothSco() */
public void stopBluetoothSco(IBinder cb){
+ Log.i(TAG, "In stopBluetoothSco()");
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if ((adapter == null) || (adapter.getState() != BluetoothAdapter.STATE_ON)) {
+ Log.i(TAG, "stopBluetoothSco(), BT is not turned ON or adapter is null");
+ return;
+ }
if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
!mSystemReady) {
return;
@@ -3673,8 +3718,7 @@
mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
setSafeMediaVolumeEnabled(true, caller);
- mMusicActiveMs = 0;
- }
+ mMusicActiveMs = 0; }
saveMusicActiveMs();
}
}
@@ -3726,7 +3770,6 @@
SystemProperties.getBoolean("audio.safemedia.force", false)
|| mContext.getResources().getBoolean(
com.android.internal.R.bool.config_safe_media_volume_enabled);
-
boolean safeMediaVolumeBypass =
SystemProperties.getBoolean("audio.safemedia.bypass", false);
@@ -4347,6 +4390,27 @@
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
}
+ /**
+ * @see AudioManager#handleBluetoothA2dpActiveDeviceChange(BluetoothDevice, int, int,
+ * boolean, int)
+ */
+ public void handleBluetoothA2dpActiveDeviceChange(
+ BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
+ int a2dpVolume) {
+ if (device == null) {
+ throw new IllegalArgumentException("Illegal null device");
+ }
+ if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
+ throw new IllegalArgumentException("invalid profile " + profile);
+ }
+ if (state != BluetoothProfile.STATE_CONNECTED
+ && state != BluetoothProfile.STATE_DISCONNECTED) {
+ throw new IllegalArgumentException("Invalid state " + state);
+ }
+ mDeviceBroker.postBluetoothA2dpDeviceConfigChangeExt(device, state, profile,
+ suppressNoisyIntent, a2dpVolume);
+ }
+
private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
AudioSystem.DEVICE_OUT_LINE |
@@ -4361,6 +4425,11 @@
newDevice, 0, null, 0);
}
+ /*package*/ void postAccessoryPlugMediaMute(int newDevice) {
+ sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_MUTE, SENDMSG_QUEUE,
+ newDevice, 0, null, 0);
+ }
+
private void onAccessoryPlugMediaUnmute(int newDevice) {
if (DEBUG_VOL) {
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
@@ -4380,6 +4449,24 @@
}
}
+ private void onAccessoryPlugMediaMute(int newDevice) {
+
+ if (DEBUG_VOL) {
+ Log.i(TAG, String.format("onAccessoryPlugMediaMute newDevice=%d [%s]",
+ newDevice, AudioSystem.getOutputDeviceName(newDevice)));
+ }
+ if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
+ && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
+ && !mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
+ && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
+ if (DEBUG_VOL) {
+ Log.i(TAG, String.format(" onAccessoryPlugMediaMute muting device=%d [%s]",
+ newDevice, AudioSystem.getOutputDeviceName(newDevice)));
+ }
+ mStreamStates[AudioSystem.STREAM_MUSIC].mute(true);
+ }
+ }
+
/**
* See AudioManager.hasHapticChannels(Uri).
*/
@@ -5136,6 +5223,10 @@
onAccessoryPlugMediaUnmute(msg.arg1);
break;
+ case MSG_ACCESSORY_PLUG_MEDIA_MUTE:
+ onAccessoryPlugMediaMute(msg.arg1);
+ break;
+
case MSG_PERSIST_MUSIC_ACTIVE_MS:
final int musicActiveMs = msg.arg1;
Settings.Secure.putIntForUser(mContentResolver,
@@ -5395,8 +5486,7 @@
UserManager.DISALLOW_RECORD_AUDIO, false, userId);
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
- if (state == BluetoothAdapter.STATE_OFF ||
- state == BluetoothAdapter.STATE_TURNING_OFF) {
+ if (state == BluetoothAdapter.STATE_OFF) {
mDeviceBroker.disconnectAllBluetoothProfiles();
}
} else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9f1a6bd..71221a7 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -39,7 +39,9 @@
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -168,6 +170,21 @@
return deviceName;
}
+ /*packages*/ @NonNull static boolean isTwsPlusSwitch(@NonNull BluetoothDevice device,
+ String address) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (device == null || adapter.getRemoteDevice(address) == null ||
+ device.getTwsPlusPeerAddress() == null) {
+ return false;
+ }
+ if (device.isTwsPlusDevice() &&
+ adapter.getRemoteDevice(address).isTwsPlusDevice() &&
+ device.getTwsPlusPeerAddress().equals(address)) {
+ Log.i(TAG,"isTwsPlusSwitch true");
+ return true;
+ }
+ return false;
+ }
//----------------------------------------------------------------------
// Interface for AudioDeviceBroker
@@ -175,6 +192,9 @@
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onSystemReady() {
mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In onSystemReady(), calling resetBluetoothSco()");
+ }
resetBluetoothSco();
getBluetoothHeadset();
@@ -245,6 +265,75 @@
return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
}
+ //SCO device tracking for TWSPLUS device
+ private HashMap<BluetoothDevice, Integer> mScoClientDevices =
+ new HashMap<BluetoothDevice, Integer>();
+
+ private void updateTwsPlusScoState(BluetoothDevice device, Integer state) {
+ if (mScoClientDevices.containsKey(device)) {
+ Integer prevState = mScoClientDevices.get(device);
+ Log.i(TAG, "updateTwsPlusScoState: prevState: " + prevState + "state: " + state);
+ if (state != prevState) {
+ mScoClientDevices.remove(device);
+ mScoClientDevices.put(device, state);
+ }
+ } else {
+ mScoClientDevices.put(device, state);
+ }
+ }
+
+ private boolean isAudioPathUp() {
+ boolean ret = false;
+ Iterator it = mScoClientDevices.entrySet().iterator();
+ for (Integer value : mScoClientDevices.values()) {
+ if (value == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+ ret = true;
+ break;
+ }
+ }
+ Log.d(TAG, "isAudioPathUp returns" + ret);
+ return ret;
+ }
+
+ private boolean checkAndUpdatTwsPlusScoState(Intent intent, Integer state) {
+ //default ret value is true
+ //so that legacy devices fallsthru
+ boolean ret = true;
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ Log.i(TAG, "device:" + device);
+
+ if (device == null) {
+ Log.e(TAG, "checkAndUpdatTwsPlusScoState: device is null");
+ //intent cant have device has null
+ //in case it is treat them as non-twsplus case and return true
+ return ret;
+ }
+
+ if (device.isTwsPlusDevice()) {
+ if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+ //if adding new Device
+ //check if there is no device already connected
+ if (isAudioPathUp()) {
+ Log.i(TAG, "No need to bringup audio-path");
+ ret = false;
+ }
+ //Update the States now
+ updateTwsPlusScoState(device, state);
+ } else {
+ //For disconnect cases, update the state first
+ updateTwsPlusScoState(device, state);
+ //if deleting new Device
+ //check if all devices are disconnected
+ if (isAudioPathUp()) {
+ Log.i(TAG, "not good to tear down audio-path");
+ ret = false;
+ }
+ }
+ }
+ Log.i(TAG, "checkAndUpdatTwsPlusScoState returns " + ret);
+ return ret;
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void receiveBtEvent(Intent intent) {
@@ -266,29 +355,42 @@
}
switch (btState) {
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+ if (checkAndUpdatTwsPlusScoState(intent,
+ BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+ mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
+ Log.i(TAG, "Audio-path brought-up");
+ }
scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
&& mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
- mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
break;
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
- scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
- // startBluetoothSco called after stopBluetoothSco
- if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
- if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
- && connectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, mScoAudioMode)) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- broadcast = false;
- break;
+ if (checkAndUpdatTwsPlusScoState(intent,
+ BluetoothHeadset.STATE_AUDIO_DISCONNECTED)) {
+ mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ // startBluetoothSco called after stopBluetoothSco
+ if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+ && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+ mBluetoothHeadsetDevice, mScoAudioMode)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ broadcast = false;
+ break;
+ }
}
+ // Tear down SCO if disconnected from external
+ clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
+ mScoAudioState = SCO_STATE_INACTIVE;
+ Log.i(TAG, "Audio-path brought-down");
}
- // Tear down SCO if disconnected from external
- clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
- mScoAudioState = SCO_STATE_INACTIVE;
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
@@ -312,6 +414,33 @@
}
}
+ /*package*/ boolean isBluetoothAudioNotConnectedToEarbud() {
+ //default value as true so that
+ //non-twsplus device case returns true
+ boolean ret = true;
+
+ if (mBluetoothHeadsetDevice != null
+ && mBluetoothHeadsetDevice.isTwsPlusDevice()) {
+ //If It is TWSplus Device, check for TWS pair device
+ //Sco state
+ String pDevAddr = mBluetoothHeadsetDevice.getTwsPlusPeerAddress();
+ if (pDevAddr != null) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothDevice peerDev = adapter.getRemoteDevice(pDevAddr);
+ Log.d(TAG, "peer device audio State: " + mBluetoothHeadset.getAudioState(peerDev));
+ if (mBluetoothHeadset.getAudioState(peerDev)
+ == BluetoothHeadset.STATE_AUDIO_CONNECTED ||
+ mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+ == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+ Log.w(TAG, "TwsPLus Case: one of eb SCO is connected");
+ ret = false;
+ }
+ }
+ }
+ Log.d(TAG, "isBluetoothAudioConnectedToEarbud returns: " + ret);
+ return ret;
+ }
+
/**
*
* @return false if SCO isn't connected
@@ -336,6 +465,9 @@
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void disconnectBluetoothSco(int exceptPid) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In disconnectBluetoothSco(), exceptPid: " + exceptPid);
+ }
checkScoAudioState();
if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
return;
@@ -426,9 +558,13 @@
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void resetBluetoothSco() {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In resetBluetoothSco(), calling clearAllScoClients()");
+ }
clearAllScoClients(0, false);
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ mScoClientDevices.clear();
AudioSystem.setParameters("A2dpSuspended=false");
mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
}
@@ -552,6 +688,12 @@
address = "";
}
String btDeviceName = getName(btDevice);
+ if (btDeviceName == null) {
+ Log.i(TAG, "handleBtScoActiveDeviceChange: btDeviceName is null," +
+ " sending empty string");
+ btDeviceName = "";
+ }
+
boolean result = false;
if (isActive) {
result |= mDeviceBroker.handleDeviceConnection(
@@ -574,20 +716,44 @@
private void setBtScoActiveDevice(BluetoothDevice btDevice) {
Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
+ if (mBluetoothHeadsetDevice != null && mBluetoothHeadsetDevice.isTwsPlusDevice()
+ && btDevice != null
+ && Objects.equals(mBluetoothHeadsetDevice.getTwsPlusPeerAddress(), btDevice.getAddress())) {
+ Log.i(TAG, "setBtScoActiveDevice: Active device switch between twsplus devices");
+ //Keep the same mBluetoothHeadsetDevice as current Active so
+ //that It tears down when active becomes null
+ return;
+ }
if (Objects.equals(btDevice, previousActiveDevice)) {
return;
}
- if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
- Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
- + previousActiveDevice);
+ String DummyAddress = "00:00:00:00:00:00";
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter == null) {
+ Log.i(TAG, "adapter is null, returning from setBtScoActiveDevice");
+ return;
}
- if (!handleBtScoActiveDeviceChange(btDevice, true)) {
- Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
- // set mBluetoothHeadsetDevice to null when failing to add new device
- btDevice = null;
+ final BluetoothDevice dummyActiveDevice = adapter.getRemoteDevice(DummyAddress);
+ if (mBluetoothHeadsetDevice == null && btDevice != null) {
+ //SCO device entry is added to mConnectedDevices hash map only when active
+ //device connects for the first time.
+ if (!handleBtScoActiveDeviceChange(dummyActiveDevice, true)) {
+ Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
+ // set mBluetoothHeadsetDevice to null when failing to add new device
+ btDevice = null;
+ }
+ }
+ if (mBluetoothHeadsetDevice != null && btDevice == null) {
+ //SCO device entry is removed from mConnectedDevices hash map only when active
+ //device is disconnected.
+ if (!handleBtScoActiveDeviceChange(dummyActiveDevice, false)) {
+ Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
+ + previousActiveDevice);
+ }
}
mBluetoothHeadsetDevice = btDevice;
if (mBluetoothHeadsetDevice == null) {
+ Log.i(TAG, "In setBtScoActiveDevice(), calling resetBluetoothSco()");
resetBluetoothSco();
}
}
@@ -597,6 +763,10 @@
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In onServiceConnected(), profile: " + profile +
+ ", proxy: "+proxy);
+ }
switch(profile) {
case BluetoothProfile.A2DP:
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -688,6 +858,7 @@
// @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
void incCount(int scoAudioMode) {
+ Log.i(TAG, "In incCount(), mStartcount = " + mStartcount);
if (!requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode)) {
Log.e(TAG, "Request sco connected with scoAudioMode("
+ scoAudioMode + ") failed");
@@ -698,17 +869,31 @@
mCb.linkToDeath(this, 0);
} catch (RemoteException e) {
// client has already died!
- Log.w(TAG, "ScoClient incCount() could not link to "
- + mCb + " binder death");
+ Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
}
}
- mStartcount++;
+ //mStartCount should always be either 0 or 1 only if the startBluetoothSco
+ //is called by the same app multiple times by mistake. This will ensure that
+ //SCO gets disconnected when app calls stopBluetoothSco only once.
+ //Also, if SCO is already there, we just need to select the SCO devices by
+ //calling setBluetoothScoOn(true) in system context.
+ if (mStartcount == 1) {
+ Log.i(TAG, "mStartcount is 1, calling setBluetoothScoOn(true)"
+ + "in system context");
+ mDeviceBroker.setBluetoothScoOn(true, "BtHelper.incCount");
+ } else if (mStartcount == 0) {
+ mStartcount++;
+ Log.i(TAG, "mStartcount is 0, incrementing by 1");
+ }
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
// @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
void decCount() {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In decCount(), mStartcount: " + mStartcount);
+ }
if (mStartcount == 0) {
Log.w(TAG, "ScoClient.decCount() already 0");
} else {
@@ -730,6 +915,10 @@
// @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
void clearCount(boolean stopSco) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In clearCount(), stopSco: " + stopSco + ", mStartcount: "
+ + mStartcount);
+ }
if (mStartcount != 0) {
try {
mCb.unlinkToDeath(this, 0);
@@ -740,7 +929,7 @@
}
mStartcount = 0;
if (stopSco) {
- requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+ boolean ScoState = requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
}
}
@@ -761,6 +950,9 @@
for (ScoClient mScoClient : mScoClients) {
count += mScoClient.getCount();
}
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In totalCount(), count: " + count);
+ }
return count;
}
@@ -768,6 +960,10 @@
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
private boolean requestScoState(int state, int scoAudioMode) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In requestScoState(), state: " + state + ", scoAudioMode: "
+ + scoAudioMode);
+ }
checkScoAudioState();
int clientCount = totalCount();
if (clientCount != 0) {
@@ -840,7 +1036,7 @@
case SCO_STATE_DEACTIVATE_REQ:
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
- break;
+ return false;
default:
Log.w(TAG, "requestScoState: failed to connect in state "
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
@@ -908,12 +1104,28 @@
private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
BluetoothDevice device, int scoAudioMode) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In disconnectBluetoothScoAudioHelper(), scoAudioMode: " + scoAudioMode +
+ ", bluetoothHeadset: " + bluetoothHeadset + ", BluetoothDevice: " + device);
+ }
switch (scoAudioMode) {
case SCO_MODE_RAW:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In disconnectBluetoothScoAudioHelper(), calling "
+ + "disconnectAudio()");
+ }
return bluetoothHeadset.disconnectAudio();
case SCO_MODE_VIRTUAL_CALL:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In disconnectBluetoothScoAudioHelper(), calling " +
+ "stopScoUsingVirtualVoiceCall()");
+ }
return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
case SCO_MODE_VR:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In disconnectBluetoothScoAudioHelper(), calling " +
+ "stopVoiceRecognition()");
+ }
return bluetoothHeadset.stopVoiceRecognition(device);
default:
return false;
@@ -922,12 +1134,27 @@
private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
BluetoothDevice device, int scoAudioMode) {
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In connectBluetoothScoAudioHelper(), scoAudioMode: " + scoAudioMode +
+ ", bluetoothHeadset: " + bluetoothHeadset + ", BluetoothDevice: " + device);
+ }
switch (scoAudioMode) {
case SCO_MODE_RAW:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In connectBluetoothScoAudioHelper(), calling connectAudio()");
+ }
return bluetoothHeadset.connectAudio();
case SCO_MODE_VIRTUAL_CALL:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In connectBluetoothScoAudioHelper(), calling "
+ + "startScoUsingVirtualVoiceCall()");
+ }
return bluetoothHeadset.startScoUsingVirtualVoiceCall();
case SCO_MODE_VR:
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In connectBluetoothScoAudioHelper(), calling "
+ + "startVoiceRecognition()");
+ }
return bluetoothHeadset.startVoiceRecognition(device);
default:
return false;
@@ -942,6 +1169,9 @@
!= BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
+ if (AudioService.DEBUG_SCO) {
+ Log.i(TAG, "In checkScoAudioState(), mScoAudioState: " + mScoAudioState);
+ }
}
@@ -1005,6 +1235,12 @@
return AudioSystem.AUDIO_FORMAT_APTX_HD;
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
return AudioSystem.AUDIO_FORMAT_LDAC;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_CELT:
+ return AudioSystem.AUDIO_FORMAT_CELT;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE:
+ return AudioSystem.AUDIO_FORMAT_APTX_ADAPTIVE;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP:
+ return AudioSystem.AUDIO_FORMAT_APTX_TWSP;
default:
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 9bae902..37daec6 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -173,6 +173,7 @@
// keepalives are sent cannot be reused by another app even if the fd gets closed by
// the user. A null is acceptable here for backward compatibility of PacketKeepalive
// API.
+ // TODO: don't accept null fd after legacy packetKeepalive API is removed.
try {
if (fd != null) {
mFd = Os.dup(fd);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index aea6d8d..2008819 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -29,11 +29,13 @@
import android.net.RouteInfo;
import android.os.INetworkManagementService;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.ServiceSpecificException;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.server.NetPluginDelegate;
import com.android.server.net.BaseNetworkObserver;
import java.net.Inet4Address;
@@ -87,6 +89,12 @@
private Inet6Address mIPv6Address;
private State mState = State.IDLE;
+ /**
+ * Used to determine if Android XLAT is required or not
+ * which defaults to false
+ */
+ private static final String xlatRequired = "persist.vendor.net.doxlat";
+
public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
INetworkManagementService nmService) {
mDnsResolver = dnsResolver;
@@ -106,6 +114,7 @@
@VisibleForTesting
protected static boolean requiresClat(NetworkAgentInfo nai) {
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
+ final int netType = nai.networkInfo.getType();
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
@@ -118,7 +127,17 @@
// If the network tells us it doesn't use clat, respect that.
final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat;
- return supported && connected && isIpv6OnlyNetwork && !skip464xlat;
+ boolean androidXlatEnabled = true;
+ if(netType == ConnectivityManager.TYPE_MOBILE) {
+ final String xlatConfigValue = NetPluginDelegate.getConfig(xlatRequired, "true");
+ if(xlatConfigValue != null && xlatConfigValue.equals("false")){
+ Slog.i(TAG, "Android Xlat is disabled");
+ androidXlatEnabled = false;
+ }
+ }
+
+ return supported && connected && isIpv6OnlyNetwork &&
+ !skip464xlat && androidXlatEnabled;
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 96b7cb3..115071a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.annotation.NonNull;
import android.content.Context;
import android.net.IDnsResolver;
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index d13e675..2c76c21 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -33,6 +33,7 @@
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b3804c4..a3d9667 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -31,6 +31,7 @@
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
+import static android.net.ConnectivityManager.TETHERING_WIGIG;
import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
@@ -90,6 +91,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -336,7 +338,7 @@
if (up) {
maybeTrackNewInterfaceLocked(iface);
} else {
- if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
+ if (ifaceNameToType(iface) == TETHERING_WIGIG) {
stopTrackingInterfaceLocked(iface);
} else {
// Ignore usb0 down after enabling RNDIS.
@@ -358,6 +360,10 @@
final TetheringConfiguration cfg = mConfig;
if (cfg.isWifi(iface)) {
+ String wigigIface = SystemProperties.get("persist.vendor.wigig.interface", "wigig0");
+ if (wigigIface.equals(iface)) {
+ return TETHERING_WIGIG;
+ }
return TETHERING_WIFI;
} else if (cfg.isWifiP2p(iface)) {
return TETHERING_WIFI_P2P;
@@ -924,7 +930,12 @@
}
if (!TextUtils.isEmpty(ifname)) {
- maybeTrackNewInterfaceLocked(ifname);
+ final int interfaceType = ifaceNameToType(ifname);
+ if (interfaceType == TETHERING_INVALID) {
+ mLog.log(ifname + " is not a tetherable iface, ignoring");
+ return;
+ }
+ maybeTrackNewInterfaceLocked(ifname, interfaceType);
changeInterfaceState(ifname, ipServingMode);
} else {
mLog.e(String.format(
@@ -1171,7 +1182,8 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
+ mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(
+ mNotifyList, mLog);
mOffload = new OffloadWrapper();
setInitialState(mInitialState);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index a1b94ca..5ffd766 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -38,6 +38,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.os.SystemProperties;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
@@ -100,6 +101,7 @@
public final int provisioningCheckPeriod;
public final int subId;
+ private static String fstInterfaceName = "bond0";
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
@@ -111,7 +113,11 @@
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
- tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
+ if (SystemProperties.getInt("persist.vendor.fst.softap.en", 0) == 1) {
+ tetherableWifiRegexs = new String[] { fstInterfaceName };
+ } else {
+ tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
+ }
tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs);
tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
@@ -133,6 +139,14 @@
configLog.log(toString());
}
+ public static void setFstInterfaceName(String name) {
+ fstInterfaceName = name;
+ }
+
+ public static String getFstInterfaceName() {
+ return fstInterfaceName;
+ }
+
public boolean isUsb(String iface) {
return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 3a9e21f..58a5745 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -491,7 +491,7 @@
public NetworkState ns = null;
}
- private static TypeStatePair findFirstAvailableUpstreamByType(
+ private TypeStatePair findFirstAvailableUpstreamByType(
Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes,
boolean isCellularUpstreamPermitted) {
final TypeStatePair result = new TypeStatePair();
@@ -512,13 +512,22 @@
nc.setSingleUid(Process.myUid());
for (NetworkState value : netStates) {
- if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
+ try {
+ // Check for both default Network and capabilities match.
+ // This avoids in picking the wrong interface(MOBILE) in
+ // STA+SAP scenarios where WIFI is preferred Network.
+ // In DUN tethering scenarios, check if the request type is
+ // DUN and capabilities match.
+ if ((type == TYPE_MOBILE_DUN || type == cm().getActiveNetworkInfo().getType())
+ && (nc.satisfiedByNetworkCapabilities(value.networkCapabilities))) {
+ result.type = type;
+ result.ns = value;
+ return result;
+ }
+ } catch (NullPointerException npe) {
+ Log.e(TAG, "Null pointer exception in getActiveNetworkInfo", npe);
continue;
}
-
- result.type = type;
- result.ns = value;
- return result;
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c466640..0c354fc 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -86,6 +86,7 @@
import android.util.Spline;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -216,6 +217,7 @@
private final SparseArray<LogicalDisplay> mLogicalDisplays =
new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+ private int mNextBuiltInDisplayId = 4096;
// List of all display transaction listeners.
private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
@@ -1003,7 +1005,7 @@
return null;
}
- final int displayId = assignDisplayIdLocked(isDefault);
+ final int displayId = assignDisplayIdLocked(isDefault, deviceInfo.address);
final int layerStack = assignLayerStackLocked(displayId);
LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
@@ -1036,6 +1038,19 @@
return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
}
+ private int assignDisplayIdLocked(boolean isDefault, DisplayAddress address) {
+ boolean isDisplayBuiltIn = false;
+ if (address instanceof DisplayAddress.Physical) {
+ isDisplayBuiltIn =
+ (((DisplayAddress.Physical) address).getPort() < 0);
+ }
+ if (!isDefault && isDisplayBuiltIn) {
+ return mNextBuiltInDisplayId++;
+ }
+
+ return assignDisplayIdLocked(isDefault);
+ }
+
private int assignLayerStackLocked(int displayId) {
// Currently layer stacks and display ids are the same.
// This need not be the case.
diff --git a/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java b/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java
new file mode 100644
index 0000000..1be474b
--- /dev/null
+++ b/services/core/java/com/android/server/display/ExtendedRemoteDisplayHelper.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.server.display;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import android.media.RemoteDisplay;
+import android.os.Handler;
+import android.util.Slog;
+import android.content.Context;
+
+class ExtendedRemoteDisplayHelper {
+ private static final String TAG = "ExtendedRemoteDisplayHelper";
+
+ // ExtendedRemoteDisplay class
+ // ExtendedRemoteDisplay is an enhanced RemoteDisplay. It has
+ // similar interface as RemoteDisplay class
+ private static Class sExtRemoteDisplayClass;
+
+ // Method object for the API ExtendedRemoteDisplay.Listen
+ // ExtendedRemoteDisplay.Listen has the same API signature as
+ // RemoteDisplay.Listen except for an additional argument to pass the
+ // Context
+ private static Method sExtRemoteDisplayListen;
+
+ // Method Object for the API ExtendedRemoteDisplay.Dispose
+ // ExtendedRemoteDisplay.Dispose follows the same API signature as
+ // RemoteDisplay.Dispose
+ private static Method sExtRemoteDisplayDispose;
+
+ static {
+ //Check availability of ExtendedRemoteDisplay runtime
+ try {
+ sExtRemoteDisplayClass = Class.forName("com.qualcomm.wfd.ExtendedRemoteDisplay");
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay Not available.");
+ }
+
+ if(sExtRemoteDisplayClass != null) {
+ // If ExtendedRemoteDisplay is available find the methods
+ Slog.i(TAG, "ExtendedRemoteDisplay Is available. Find Methods");
+ try {
+ Class args[] = {
+ String.class,
+ RemoteDisplay.Listener.class,
+ Handler.class, Context.class
+ };
+ sExtRemoteDisplayListen = sExtRemoteDisplayClass.getDeclaredMethod("listen", args);
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen Not available.");
+ }
+
+ try {
+ Class args[] = {};
+ sExtRemoteDisplayDispose = sExtRemoteDisplayClass.getDeclaredMethod("dispose", args);
+ } catch (Throwable t) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose Not available.");
+ }
+ }
+ }
+
+ /**
+ * Starts listening for displays to be connected on the specified interface.
+ *
+ * @param iface The interface address and port in the form "x.x.x.x:y".
+ * @param listener The listener to invoke
+ * when displays are connected or disconnected.
+ * @param handler The handler on which to invoke the listener.
+ * @param context The current service context
+ * */
+ public static Object listen(String iface, RemoteDisplay.Listener listener,
+ Handler handler, Context context)
+ {
+ Object extRemoteDisplay = null;
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen");
+
+ if(sExtRemoteDisplayListen != null && sExtRemoteDisplayDispose != null){
+ try {
+ extRemoteDisplay = sExtRemoteDisplayListen.invoke(null,
+ iface, listener, handler, context);
+ } catch (InvocationTargetException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen - InvocationTargetException");
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(e);
+ }
+ } catch (IllegalAccessException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.listen -IllegalAccessException");
+ e.printStackTrace();
+ }
+ }
+ return extRemoteDisplay;
+ }
+
+ /**
+ * Disconnects the remote display and stops listening for new connections.
+ */
+ public static void dispose(Object extRemoteDisplay) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose");
+ try{
+ sExtRemoteDisplayDispose.invoke(extRemoteDisplay);
+ } catch (InvocationTargetException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose - InvocationTargetException");
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(e);
+ }
+ } catch (IllegalAccessException e) {
+ Slog.i(TAG, "ExtendedRemoteDisplay.dispose-IllegalAccessException");
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Checks if ExtendedRemoteDisplay is available
+ */
+ public static boolean isAvailable()
+ {
+ if(sExtRemoteDisplayClass != null &&
+ sExtRemoteDisplayDispose != null &&
+ sExtRemoteDisplayListen != null) {
+ Slog.i(TAG, "ExtendedRemoteDisplay isAvailable() : Available.");
+ return true;
+ }
+ Slog.i(TAG, "ExtendedRemoteDisplay isAvailable() : Not Available.");
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b..e063d85 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -417,6 +417,8 @@
}
final Resources res = getOverlayContext().getResources();
+ final boolean isBuiltIn = ((mInfo.address) != null) ?
+ (((DisplayAddress.Physical) mInfo.address).getPort() < 0) : false;
if (mIsInternal) {
mInfo.name = res.getString(
com.android.internal.R.string.display_manager_built_in_display_name);
@@ -438,6 +440,26 @@
mInfo.xDpi = phys.xDpi;
mInfo.yDpi = phys.yDpi;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
+ } else if (isBuiltIn) {
+ mInfo.type = Display.TYPE_BUILT_IN;
+ mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
+ mInfo.name = getContext().getResources().getString(
+ com.android.internal.R.string.display_manager_built_in_display_name);
+ mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+
+ if (SystemProperties.getBoolean(
+ "vendor.display.builtin_presentation", false)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
+ } else {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+ }
+
+ if (!SystemProperties.getBoolean(
+ "vendor.display.builtin_mirroring", false)) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+ }
+
+ mInfo.setAssumedDensityForExternalDisplay(phys.width, phys.height);
} else {
mInfo.displayCutout = null;
mInfo.type = Display.TYPE_HDMI;
@@ -711,6 +733,9 @@
SurfaceControl.setAllowedDisplayConfigs(getDisplayTokenLocked(), allowedPhysIndexes);
int activePhysIndex = SurfaceControl.getActiveConfig(getDisplayTokenLocked());
+ if (activePhysIndex < 0) {
+ return false;
+ }
return updateActiveModeLocked(activePhysIndex);
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index d9d46b8..32d1f59 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -42,11 +42,14 @@
import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Handler;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
import android.view.Surface;
import java.io.PrintWriter;
+import java.lang.StackTraceElement;
+import java.lang.Thread;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
@@ -69,8 +72,10 @@
*/
final class WifiDisplayController implements DumpUtils.Dump {
private static final String TAG = "WifiDisplayController";
- private static final boolean DEBUG = false;
-
+ private static final boolean DEBUG =
+ SystemProperties.getBoolean("persist.vendor.debug.wfdcdbg",false);
+ private static final boolean DEBUGV =
+ SystemProperties.getBoolean("persist.vendor.debug.wfdcdbgv",false);
private static final int DEFAULT_CONTROL_PORT = 7236;
private static final int MAX_THROUGHPUT = 50;
private static final int CONNECTION_TIMEOUT_SECONDS = 30;
@@ -136,6 +141,10 @@
// Number of connection retries remaining.
private int mConnectionRetriesLeft;
+ // The Extended remote display that is listening on the connection.
+ // Created after the Wifi P2P network is connected.
+ private Object mExtRemoteDisplay;
+
// The remote display that is listening on the connection.
// Created after the Wifi P2P network is connected.
private RemoteDisplay mRemoteDisplay;
@@ -188,6 +197,16 @@
updateSettings();
}
+ private Channel getWifiP2pChannel() {
+ if(mWifiP2pChannel == null) {
+ mWifiP2pChannel = mWifiP2pManager.initialize(mContext, mHandler.getLooper(), null);
+ if(DEBUG) {
+ Slog.d(TAG, "Creating WifiP2pChannel");
+ }
+ }
+ return mWifiP2pChannel;
+ }
+
/**
* Used to lazily retrieve WifiP2pManager service.
*/
@@ -246,6 +265,35 @@
}
}
+ private void dump() {
+ Slog.d(TAG,"mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
+ Slog.d(TAG,"mWifiP2pEnabled=" + mWifiP2pEnabled);
+ Slog.d(TAG,"mWfdEnabled=" + mWfdEnabled);
+ Slog.d(TAG,"mWfdEnabling=" + mWfdEnabling);
+ Slog.d(TAG,"mNetworkInfo=" + mNetworkInfo);
+ Slog.d(TAG,"mScanRequested=" + mScanRequested);
+ Slog.d(TAG,"mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
+ Slog.d(TAG,"mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
+ Slog.d(TAG,"mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+ Slog.d(TAG,"mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
+ Slog.d(TAG,"mCancelingDisplay=" + describeWifiP2pDevice(mCancelingDevice));
+ Slog.d(TAG,"mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
+ Slog.d(TAG,"mConnectionRetriesLeft=" + mConnectionRetriesLeft);
+ Slog.d(TAG,"mRemoteDisplay=" + mRemoteDisplay);
+ Slog.d(TAG,"mRemoteDisplayInterface=" + mRemoteDisplayInterface);
+ Slog.d(TAG,"mRemoteDisplayConnected=" + mRemoteDisplayConnected);
+ Slog.d(TAG,"mAdvertisedDisplay=" + mAdvertisedDisplay);
+ Slog.d(TAG,"mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
+ Slog.d(TAG,"mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
+ Slog.d(TAG,"mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
+ Slog.d(TAG,"mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
+
+ Slog.d(TAG,"mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
+ for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
+ Slog.d(TAG," " + describeWifiP2pDevice(device));
+ }
+ }
+
public void requestStartScan() {
if (!mScanRequested) {
mScanRequested = true;
@@ -296,7 +344,7 @@
wfdInfo.setSessionAvailable(true);
wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
- mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+ mWifiP2pManager.setWFDInfo(getWifiP2pChannel(), wfdInfo, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
@@ -324,7 +372,7 @@
if (mWfdEnabled || mWfdEnabling) {
WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
wfdInfo.setWfdEnabled(false);
- mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+ mWifiP2pManager.setWFDInfo(getWifiP2pChannel(), wfdInfo, new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
@@ -367,7 +415,9 @@
}
private void updateScanState() {
- if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
+ if (mScanRequested && mWfdEnabled &&
+ (mDesiredDevice == null) && (mConnectedDevice == null)
+ && (mDisconnectingDevice == null)) {
if (!mDiscoverPeersInProgress) {
Slog.i(TAG, "Starting Wifi display scan.");
mDiscoverPeersInProgress = true;
@@ -393,7 +443,7 @@
}
private void tryDiscoverPeers() {
- mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
+ mWifiP2pManager.discoverPeers(getWifiP2pChannel(), new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
@@ -421,7 +471,7 @@
}
private void stopPeerDiscovery() {
- mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
+ mWifiP2pManager.stopPeerDiscovery(getWifiP2pChannel(), new ActionListener() {
@Override
public void onSuccess() {
if (DEBUG) {
@@ -439,7 +489,7 @@
}
private void requestPeers() {
- mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
+ mWifiP2pManager.requestPeers(getWifiP2pChannel(), new PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
if (DEBUG) {
@@ -543,6 +593,10 @@
return;
}
+ if (handlePreExistingConnection(device)) {
+ Slog.i(TAG, "already handle the preexisting p2p connection status");
+ return;
+ }
mDesiredDevice = device;
mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
updateConnection();
@@ -567,20 +621,35 @@
* connection is established (or not).
*/
private void updateConnection() {
+ if(DEBUGV) {
+ //new Throwable("WFD_DBG").printStackTrace();
+ StackTraceElement[] st = Thread.currentThread().getStackTrace();
+ for(int i = 2 ; i < st.length && i < 5; i++) {
+ Slog.i(TAG,st[i].toString());
+ }
+ dump();
+ }
// Step 0. Stop scans if necessary to prevent interference while connected.
// Resume scans later when no longer attempting to connect.
updateScanState();
// Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one.
- if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
- Slog.i(TAG, "Stopped listening for RTSP connection on " + mRemoteDisplayInterface
- + " from Wifi display: " + mConnectedDevice.deviceName);
+ if ((mRemoteDisplay != null || mExtRemoteDisplay != null) &&
+ (mConnectedDevice != mDesiredDevice)||
+ (mRemoteDisplayInterface != null && mConnectedDevice == null)) {
+ Slog.i(TAG, "Stopped listening for RTSP connection on "
+ + mRemoteDisplayInterface);
- mRemoteDisplay.dispose();
+ if(mRemoteDisplay != null) {
+ mRemoteDisplay.dispose();
+ } else if(mExtRemoteDisplay != null) {
+ ExtendedRemoteDisplayHelper.dispose(mExtRemoteDisplay);
+ }
+
+ mExtRemoteDisplay = null;
mRemoteDisplay = null;
mRemoteDisplayInterface = null;
- mRemoteDisplayConnected = false;
mHandler.removeCallbacks(mRtspTimeout);
mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
@@ -590,7 +659,7 @@
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
- if (mDisconnectingDevice != null) {
+ if (mRemoteDisplayConnected || mDisconnectingDevice != null) {
return; // wait for asynchronous callback
}
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
@@ -602,7 +671,7 @@
unadvertiseDisplay();
final WifiP2pDevice oldDevice = mDisconnectingDevice;
- mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
+ mWifiP2pManager.removeGroup(getWifiP2pChannel(), new ActionListener() {
@Override
public void onSuccess() {
Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
@@ -640,7 +709,7 @@
mHandler.removeCallbacks(mConnectionTimeout);
final WifiP2pDevice oldDevice = mCancelingDevice;
- mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
+ mWifiP2pManager.cancelConnect(getWifiP2pChannel(), new ActionListener() {
@Override
public void onSuccess() {
Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
@@ -674,6 +743,75 @@
return; // done
}
+ //Before we connect, we need to set the oldDevice to the desiredDevice to check
+ //the device on receiving callbacks from the Remote display modules
+ final WifiP2pDevice oldDevice = mDesiredDevice;
+ RemoteDisplay.Listener listener = new RemoteDisplay.Listener() {
+ @Override
+ public void onDisplayConnected(Surface surface,
+ int width, int height, int flags, int session) {
+ if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
+ Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ + mConnectedDevice.deviceName);
+ mRemoteDisplayConnected = true;
+ mHandler.removeCallbacks(mRtspTimeout);
+
+ if (mWifiDisplayCertMode) {
+ mListener.onDisplaySessionInfo(
+ getSessionInfo(mConnectedDeviceGroupInfo, session));
+ }
+
+ final WifiDisplay display = createWifiDisplay(mConnectedDevice);
+ advertiseDisplay(display, surface, width, height, flags);
+ }
+ }
+
+ @Override
+ public void onDisplayDisconnected() {
+ if (mConnectedDevice == oldDevice) {
+ Slog.i(TAG, "Closed RTSP connection with Wifi display: "
+ + mConnectedDevice.deviceName);
+ mHandler.removeCallbacks(mRtspTimeout);
+ mRemoteDisplayConnected = false;
+ disconnect();
+ }
+ }
+
+ @Override
+ public void onDisplayError(int error) {
+ if (mConnectedDevice == oldDevice) {
+ Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
+ + error + ": " + mConnectedDevice.deviceName);
+ mHandler.removeCallbacks(mRtspTimeout);
+ handleConnectionFailure(false);
+ }
+ }
+ };
+
+ int WFDR2Info = SystemProperties.getInt("persist.vendor.setWFDInfo.R2",0);
+ Slog.i(TAG, "WFDR2info is: " + WFDR2Info);
+ /*R1 source - R1 sink ->0
+ *R1 source - R2 sink ->1
+ *R2 source - R1 sink ->2
+ *R2 source - R2 sink ->3*/
+ if(WFDR2Info==2 || WFDR2Info==3){
+ WifiP2pWfdInfo wfdInfo = mThisDevice.wfdInfo;
+ mWifiP2pManager.setWFDR2Info(getWifiP2pChannel(), wfdInfo, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.i(TAG, "Successfully set WFD R2 info.");
+ }
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.i(TAG, "Failed to set WFD R2 info with reason " + reason + ".");
+ }
+ }
+ });
+ }
// Step 5. Try to connect.
if (mConnectedDevice == null && mConnectingDevice == null) {
Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
@@ -699,8 +837,21 @@
WifiDisplay display = createWifiDisplay(mConnectingDevice);
advertiseDisplay(display, null, 0, 0, 0);
+ if(ExtendedRemoteDisplayHelper.isAvailable()&&
+ mExtRemoteDisplay == null){
+ final int port = getPortNumber(mDesiredDevice);
+ //IP is superfluous for WFD source, and we don't have one at this stage anyway since
+ //P2P connection hasn't been established yet
+ final String iface = "255.255.255.255:" + port;
+ mRemoteDisplayInterface = iface;
+ Slog.i(TAG, "Listening for RTSP connection on " + iface
+ + " from Wifi display: " + mDesiredDevice.deviceName);
+ mExtRemoteDisplay = ExtendedRemoteDisplayHelper.listen(iface,
+ listener, mHandler, mContext);
+ }
+
final WifiP2pDevice newDevice = mDesiredDevice;
- mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
+ mWifiP2pManager.connect(getWifiP2pChannel(), config, new ActionListener() {
@Override
public void onSuccess() {
// The connection may not yet be established. We still need to wait
@@ -736,54 +887,16 @@
mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
- final WifiP2pDevice oldDevice = mConnectedDevice;
final int port = getPortNumber(mConnectedDevice);
final String iface = addr.getHostAddress() + ":" + port;
mRemoteDisplayInterface = iface;
- Slog.i(TAG, "Listening for RTSP connection on " + iface
- + " from Wifi display: " + mConnectedDevice.deviceName);
-
- mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
- @Override
- public void onDisplayConnected(Surface surface,
- int width, int height, int flags, int session) {
- if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
- Slog.i(TAG, "Opened RTSP connection with Wifi display: "
- + mConnectedDevice.deviceName);
- mRemoteDisplayConnected = true;
- mHandler.removeCallbacks(mRtspTimeout);
-
- if (mWifiDisplayCertMode) {
- mListener.onDisplaySessionInfo(
- getSessionInfo(mConnectedDeviceGroupInfo, session));
- }
-
- final WifiDisplay display = createWifiDisplay(mConnectedDevice);
- advertiseDisplay(display, surface, width, height, flags);
- }
- }
-
- @Override
- public void onDisplayDisconnected() {
- if (mConnectedDevice == oldDevice) {
- Slog.i(TAG, "Closed RTSP connection with Wifi display: "
- + mConnectedDevice.deviceName);
- mHandler.removeCallbacks(mRtspTimeout);
- disconnect();
- }
- }
-
- @Override
- public void onDisplayError(int error) {
- if (mConnectedDevice == oldDevice) {
- Slog.i(TAG, "Lost RTSP connection with Wifi display due to error "
- + error + ": " + mConnectedDevice.deviceName);
- mHandler.removeCallbacks(mRtspTimeout);
- handleConnectionFailure(false);
- }
- }
- }, mHandler, mContext.getOpPackageName());
+ if(!ExtendedRemoteDisplayHelper.isAvailable()){
+ Slog.i(TAG, "Listening for RTSP connection on " + iface
+ + " from Wifi display: " + mConnectedDevice.deviceName);
+ mRemoteDisplay = RemoteDisplay.listen(iface, listener,
+ mHandler, mContext.getOpPackageName());
+ }
// Use extended timeout value for certification, as some tests require user inputs
int rtspTimeout = mWifiDisplayCertMode ?
@@ -794,7 +907,7 @@
}
private WifiDisplaySessionInfo getSessionInfo(WifiP2pGroup info, int session) {
- if (info == null) {
+ if (info == null || info.getOwner() == null) {
return null;
}
Inet4Address addr = getInterfaceAddress(info);
@@ -828,9 +941,13 @@
mNetworkInfo = networkInfo;
if (mWfdEnabled && networkInfo.isConnected()) {
if (mDesiredDevice != null || mWifiDisplayCertMode) {
- mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
+ mWifiP2pManager.requestGroupInfo(getWifiP2pChannel(), new GroupInfoListener() {
@Override
public void onGroupInfoAvailable(WifiP2pGroup info) {
+ if(info == null) {
+ return;
+ }
+
if (DEBUG) {
Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
}
@@ -850,8 +967,9 @@
}
if (mWifiDisplayCertMode) {
- boolean owner = info.getOwner().deviceAddress
- .equals(mThisDevice.deviceAddress);
+ boolean owner = (info.getOwner() != null)?
+ info.getOwner().deviceAddress
+ .equals(mThisDevice.deviceAddress):false;
if (owner && info.getClientList().isEmpty()) {
// this is the case when we started Autonomous GO,
// and no client has connected, save group info
@@ -889,6 +1007,12 @@
disconnect();
}
+ if (mDesiredDevice != null) {
+ Slog.i(TAG, "reconnect new device: " + mDesiredDevice.deviceName);
+ updateConnection();
+ return;
+ }
+
// After disconnection for a group, for some reason we have a tendency
// to get a peer change notification with an empty list of peers.
// Perform a fresh scan.
@@ -921,7 +1045,8 @@
@Override
public void run() {
if (mConnectedDevice != null
- && mRemoteDisplay != null && !mRemoteDisplayConnected) {
+ && (mRemoteDisplay != null || mExtRemoteDisplay != null)
+ && !mRemoteDisplayConnected) {
Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
+ RTSP_TIMEOUT_SECONDS + " seconds: "
+ mConnectedDevice.deviceName);
@@ -1005,6 +1130,41 @@
mAdvertisedDisplayFlags);
}
+ private boolean handlePreExistingConnection(final WifiP2pDevice device) {
+ if (mNetworkInfo == null || !mNetworkInfo.isConnected() || mWifiDisplayCertMode) {
+ return false;
+ }
+ Slog.i(TAG, "handle the preexisting p2p connection status");
+ mWifiP2pManager.requestGroupInfo(getWifiP2pChannel(), new GroupInfoListener() {
+ @Override
+ public void onGroupInfoAvailable(WifiP2pGroup info) {
+ if (info == null) {
+ return;
+ }
+ if (info.contains(device)) {
+ Slog.i(TAG, "already connected to the desired device: " + device.deviceName);
+ updateConnection();
+ handleConnectionChanged(mNetworkInfo);
+ } else {
+ mWifiP2pManager.removeGroup(getWifiP2pChannel(), new ActionListener() {
+ @Override
+ public void onSuccess() {
+ Slog.i(TAG, "disconnect the old device");
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ Slog.i(TAG, "Failed to disconnect the old device: reason=" + reason);
+ }
+ });
+ }
+ }
+ });
+ mDesiredDevice = device;
+ mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
+ return true;
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 8bf01a3..d94a5c5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -38,6 +38,8 @@
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
+import android.net.Network;
+import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.BatteryStats;
import android.os.Binder;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9bbe628..ec56ec5 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -199,6 +199,7 @@
// Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
// Do not call into ActivityManager while holding mSpManager lock.
private final Object mSeparateChallengeLock = new Object();
+ private static final String DEFAULT_PASSWORD = "default_password";
private final DeviceProvisionedObserver mDeviceProvisionedObserver =
new DeviceProvisionedObserver();
@@ -220,6 +221,7 @@
private final SyntheticPasswordManager mSpManager;
private final KeyStore mKeyStore;
+ private static String mSavePassword = DEFAULT_PASSWORD;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
@@ -1215,6 +1217,45 @@
return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
}
+ public void retainPassword(String password) {
+ if (LockPatternUtils.isDeviceEncryptionEnabled()) {
+ if (password != null)
+ mSavePassword = password;
+ else
+ mSavePassword = DEFAULT_PASSWORD;
+ }
+ }
+
+ public void sanitizePassword() {
+ if (LockPatternUtils.isDeviceEncryptionEnabled()) {
+ mSavePassword = DEFAULT_PASSWORD;
+ }
+ }
+
+ private boolean checkCryptKeeperPermissions() {
+ boolean permission_err = false;
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CRYPT_KEEPER,
+ "no permission to get the password");
+ } catch (SecurityException e) {
+ permission_err = true;
+ }
+ return permission_err;
+ }
+
+ public String getPassword() {
+ /** if calling process does't have crypt keeper or admin permissions,
+ * throw the exception.
+ */
+ if (checkCryptKeeperPermissions())
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ "no crypt_keeper or admin permission to get the password");
+
+ return mSavePassword;
+ }
+
private void setKeystorePassword(byte[] password, int userHandle) {
final KeyStore ks = KeyStore.getInstance();
// TODO(b/120484642): Update keystore to accept byte[] passwords
@@ -1778,6 +1819,20 @@
addUserKeyAuth(userId, null, null);
}
+ private void clearUserKeyAuth(int userId, byte[] token, byte[] secret) {
+ if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
+ final UserInfo userInfo = mUserManager.getUserInfo(userId);
+ final IStorageManager storageManager = mInjector.getStorageManager();
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ storageManager.clearUserKeyAuth(userId, userInfo.serialNumber, token, secret);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("clearUserKeyAuth failed user=" + userId);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
private static byte[] secretFromCredential(LockscreenCredential credential) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
@@ -1890,7 +1945,15 @@
public VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,
ICheckCredentialProgressCallback progressCallback) {
checkPasswordReadPermission(userId);
- return doVerifyCredential(credential, CHALLENGE_NONE, 0, userId, progressCallback);
+ VerifyCredentialResponse response = doVerifyCredential(credential, CHALLENGE_NONE,
+ 0, userId, progressCallback);
+ if ((response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) &&
+ (userId == UserHandle.USER_OWNER)) {
+ //TODO(b/127810705): Update to credentials to use LockscreenCredential
+ String credentialString = credential.isNone() ? null : new String(credential.getCredential());
+ retainPassword(credentialString);
+ }
+ return response;
}
@Override
@@ -2768,7 +2831,7 @@
// during boot. Vold storage needs to be unlocked before manipulation of the keys can
// succeed.
unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
- clearUserKeyProtection(userId);
+ clearUserKeyAuth(userId, null, auth.deriveDiskEncryptionKey());
fixateNewestUserKeyAuth(userId);
unlockKeystore(auth.deriveKeyStorePassword(), userId);
setKeystorePassword(null, userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
old mode 100644
new mode 100755
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed2bb3d5..e3199e0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -474,6 +474,7 @@
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
+ android.util.SeempLog.record(90);
final int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(
callingUid, userId, true, true, "createSession");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 104ce1c..e88e64d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -270,6 +270,7 @@
import android.util.Xml;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
+import android.util.BoostFramework;
import android.view.Display;
import com.android.internal.R;
@@ -1477,6 +1478,7 @@
| FLAG_PERMISSION_REVOKED_COMPAT;
final @Nullable String mRequiredVerifierPackage;
+ final @Nullable String mOptionalVerifierPackage;
final @NonNull String mRequiredInstallerPackage;
final @NonNull String mRequiredUninstallerPackage;
final @NonNull String mRequiredPermissionControllerPackage;
@@ -3110,6 +3112,7 @@
if (!mOnlyCore) {
mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
+ mOptionalVerifierPackage = getOptionalVerifierLPr();
mRequiredInstallerPackage = getRequiredInstallerLPr();
mRequiredUninstallerPackage = getRequiredUninstallerLPr();
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
@@ -3127,6 +3130,7 @@
SharedLibraryInfo.VERSION_UNDEFINED);
} else {
mRequiredVerifierPackage = null;
+ mOptionalVerifierPackage = null;
mRequiredInstallerPackage = null;
mRequiredUninstallerPackage = null;
mIntentFilterVerifierComponent = null;
@@ -3531,6 +3535,14 @@
UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
if (matches.size() == 1) {
return matches.get(0).getComponentInfo().packageName;
+ } else if (matches.size() > 1) {
+ String optionalVerifierName = mContext.getResources().getString(R.string.config_optionalPackageVerifierName);
+ if (TextUtils.isEmpty(optionalVerifierName))
+ return matches.get(0).getComponentInfo().packageName;
+ for (int i = 0; i < matches.size(); i++) {
+ if (!matches.get(i).getComponentInfo().packageName.contains(optionalVerifierName))
+ return matches.get(i).getComponentInfo().packageName;
+ }
} else if (matches.size() == 0) {
Log.e(TAG, "There should probably be a verifier, but, none were found");
return null;
@@ -3538,6 +3550,25 @@
throw new RuntimeException("There must be exactly one verifier; found " + matches);
}
+ private @Nullable String getOptionalVerifierLPr() {
+ final Intent intent = new Intent("com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION");
+
+ final List<ResolveInfo> matches = queryIntentReceiversInternal(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.USER_SYSTEM, false /*allowDynamicSplits*/);
+ if (matches.size() >= 1) {
+ String optionalVerifierName = mContext.getResources().getString(R.string.config_optionalPackageVerifierName);
+ if (TextUtils.isEmpty(optionalVerifierName))
+ return null;
+ for (int i = 0; i < matches.size(); i++) {
+ if (matches.get(i).getComponentInfo().packageName.contains(optionalVerifierName)) {
+ return matches.get(i).getComponentInfo().packageName;
+ }
+ }
+ }
+ return null;
+ }
+
private @NonNull String getRequiredSharedLibraryLPr(String name, int version) {
synchronized (mLock) {
SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version);
@@ -14190,9 +14221,14 @@
final int requiredUid = mRequiredVerifierPackage == null ? -1
: getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
verifierUser.getIdentifier());
+
+ final int optionalUid = mOptionalVerifierPackage == null ? -1
+ : getPackageUid(mOptionalVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+ verifierUser.getIdentifier());
+
final int installerUid =
verificationInfo == null ? -1 : verificationInfo.installerUid;
- if (!origin.existing && requiredUid != -1
+ if (!origin.existing && (requiredUid != -1 || optionalUid != -1)
&& isVerificationEnabled(
verifierUser.getIdentifier(), installFlags, installerUid)) {
final Intent verification = new Intent(
@@ -14286,10 +14322,39 @@
}
}
- final ComponentName requiredVerifierComponent = matchComponentForVerifier(
- mRequiredVerifierPackage, receivers);
+ if (mOptionalVerifierPackage != null) {
+ final Intent optionalIntent = new Intent(verification);
+ optionalIntent.setAction("com.qualcomm.qti.intent.action.PACKAGE_NEEDS_OPTIONAL_VERIFICATION");
+ final List<ResolveInfo> optional_receivers = queryIntentReceiversInternal(optionalIntent,
+ PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier(), false /*allowDynamicSplits*/);
+ final ComponentName optionalVerifierComponent = matchComponentForVerifier(
+ mOptionalVerifierPackage, optional_receivers);
+ optionalIntent.setComponent(optionalVerifierComponent);
+ verificationState.addOptionalVerifier(optionalUid);
+ if (mRequiredVerifierPackage != null) {
+ mContext.sendBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+ } else {
+ mContext.sendOrderedBroadcastAsUser(optionalIntent, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);
+ msg.arg1 = verificationId;
+ mHandler.sendMessageDelayed(msg, getVerificationTimeout());
+ }
+ }, null, 0, null, null);
+
+ /*
+ * We don't want the copy to proceed until
+ * verification succeeds.
+ */
+ mVerificationCompleted = false;
+ }
+ }
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
+ final ComponentName requiredVerifierComponent = matchComponentForVerifier(
+ mRequiredVerifierPackage, receivers);
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
/*
@@ -15051,6 +15116,8 @@
final int installReason = installArgs.installReason;
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
+ if (pkgName != null)
+ acquireUxPerfLock(BoostFramework.UXE_EVENT_PKG_INSTALL, pkgName, 0);
synchronized (mLock) {
// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
mPermissionManager.updatePermissions(pkgName, pkg);
@@ -16231,6 +16298,11 @@
// on the device; we should replace it.
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
+ acquireUxPerfLock(BoostFramework.UXE_EVENT_PKG_INSTALL, pkgName, 1);
+ BoostFramework mPerf = new BoostFramework();
+ if (mPerf != null) {
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_APP_UPDATE, pkgName, -1, 0);
+ }
}
// Child packages are installed through the parent package
@@ -17506,9 +17578,19 @@
}
}
+ if (res && packageName != null) {
+ acquireUxPerfLock(BoostFramework.UXE_EVENT_PKG_UNINSTALL, packageName, userId);
+ }
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ private void acquireUxPerfLock(int opcode, String pkgName, int dat) {
+ BoostFramework ux_perf = new BoostFramework();
+ if (ux_perf != null) {
+ ux_perf.perfUXEngine_events(opcode, 0, pkgName, dat);
+ }
+ }
+
static class PackageRemovedInfo {
final PackageSender packageSender;
String removedPackage;
@@ -21213,7 +21295,7 @@
final StorageManager sm = mInjector.getStorageManager();
UserManagerInternal umInternal = mInjector.getUserManagerInternal();
for (UserInfo user : mUserManager.getUsers(false /* includeDying */)) {
- final int flags;
+ int flags = 0;
if (umInternal.isUserUnlockingOrUnlocked(user.id)) {
flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
} else if (umInternal.isUserRunning(user.id)) {
@@ -21221,9 +21303,12 @@
} else {
continue;
}
-
+ if ((vol.disk.flags & DiskInfo.FLAG_UFS_CARD) == DiskInfo.FLAG_UFS_CARD) {
+ flags = flags | DiskInfo.FLAG_UFS_CARD;
+ }
+ final int pflags = flags;
try {
- sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
+ sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, pflags);
synchronized (mInstallLock) {
reconcileAppsDataLI(volumeUuid, user.id, flags, true /* migrateAppData */);
}
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index c50bf59..673ee8f 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -43,6 +43,14 @@
private boolean mRequiredVerificationPassed;
+ private int mOptionalVerifierUid;
+
+ private boolean mHasOptionalVerifier;
+
+ private boolean mOptionalVerificationComplete;
+
+ private boolean mOptionalVerificationPassed;
+
private boolean mExtendedTimeout;
/**
@@ -73,6 +81,11 @@
mSufficientVerifierUids.put(uid, true);
}
+ public void addOptionalVerifier(int uid) {
+ mOptionalVerifierUid = uid;
+ mHasOptionalVerifier = true;
+ }
+
/**
* Should be called when a verification is received from an agent so the
* state of the package verification can be tracked.
@@ -94,6 +107,16 @@
mRequiredVerificationPassed = false;
}
return true;
+ } else if (mHasOptionalVerifier && uid == mOptionalVerifierUid) {
+ mOptionalVerificationComplete = true;
+ switch (code) {
+ case PackageManager.VERIFICATION_ALLOW:
+ mOptionalVerificationPassed = true;
+ break;
+ default:
+ mOptionalVerificationPassed = false;
+ }
+ return true;
} else {
if (mSufficientVerifierUids.get(uid)) {
if (code == PackageManager.VERIFICATION_ALLOW) {
@@ -121,7 +144,11 @@
* @return {@code true} when verification is considered complete
*/
boolean isVerificationComplete() {
- if (!mRequiredVerificationComplete) {
+ if (mRequiredVerifierUid != -1 && !mRequiredVerificationComplete) {
+ return false;
+ }
+
+ if (mHasOptionalVerifier && !mOptionalVerificationComplete) {
return false;
}
@@ -139,7 +166,11 @@
* @return {@code true} if installation should be allowed
*/
boolean isInstallAllowed() {
- if (!mRequiredVerificationPassed) {
+ if (mRequiredVerifierUid != -1 && !mRequiredVerificationPassed) {
+ return false;
+ }
+
+ if (mHasOptionalVerifier && !mOptionalVerificationPassed) {
return false;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5e1d93f..a7c91a0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -752,6 +752,15 @@
}
};
+ private UEventObserver mExtEventObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (event.get("status") != null) {
+ mDefaultDisplayPolicy.setHdmiPlugged("connected".equals(event.get("status")));
+ }
+ }
+ };
+
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
@@ -3630,6 +3639,7 @@
void initializeHdmiStateInternal() {
boolean plugged = false;
+ mExtEventObserver.startObserving("mdss_mdp/drm/card");
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 0a6b38f..fa4c456 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -73,6 +73,12 @@
private static final int PACKAGE_MANAGER_STOP_PERCENT = 6;
private static final int RADIO_STOP_PERCENT = 18;
private static final int MOUNT_SERVICE_STOP_PERCENT = 20;
+ // Time we should wait for vendor subsystem shutdown
+ // Sleep times(ms) between checks of the vendor subsystem state
+ private static final int VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS = 100;
+ // Max time we wait for vendor subsystems to shut down before resuming
+ // with full system shutdown
+ private static final int VENDOR_SUBSYS_MAX_WAIT_MS = 10000;
// length of vibration before shutting down
private static final int SHUTDOWN_VIBRATE_MS = 500;
@@ -655,6 +661,59 @@
* @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
+ String subsysProp;
+ subsysProp = SystemProperties.get("vendor.peripheral.shutdown_critical_list",
+ "ERROR");
+ //If we don't have the shutdown critical subsystem list we can't
+ //really do anything. Proceed with full system shutdown.
+ if (!subsysProp.equals("ERROR")) {
+ Log.i(TAG, "Shutdown critical subsyslist is :"+subsysProp+": ");
+ Log.i(TAG, "Waiting for a maximum of " +
+ (VENDOR_SUBSYS_MAX_WAIT_MS) + "ms");
+ String[] subsysList = subsysProp.split(" ");
+ int wait_count = 0;
+ boolean okToShutdown = true;
+ String subsysState;
+ int subsysListLength = subsysList.length;
+ do {
+ okToShutdown = true;
+ for (int i = 0; i < subsysListLength; i++) {
+ subsysState =
+ SystemProperties.get(
+ "vendor.peripheral." +
+ subsysList[i] +
+ ".state",
+ "ERROR");
+ if(subsysState.equals("ONLINE")) {
+ //We only want to delay shutdown while
+ //one of the shutdown critical
+ //subsystems still shows as 'ONLINE'.
+ okToShutdown = false;
+ }
+ }
+ if (okToShutdown == false) {
+ SystemClock.sleep(VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS);
+ wait_count++;
+ }
+ } while (okToShutdown != true &&
+ wait_count < (VENDOR_SUBSYS_MAX_WAIT_MS/VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS));
+ if (okToShutdown != true) {
+ for (int i = 0; i < subsysList.length; i++) {
+ subsysState =
+ SystemProperties.get(
+ "vendor.peripheral." +
+ subsysList[i] +
+ ".state",
+ "ERROR");
+ if(subsysState.equals("ONLINE")) {
+ Log.w(TAG, "Subsystem " + subsysList[i]+
+ "did not shut down within timeout");
+ }
+ }
+ } else {
+ Log.i(TAG, "Vendor subsystem(s) shutdown successful");
+ }
+ }
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 48a7b73..d2b115c 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -41,6 +41,8 @@
import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
@@ -72,6 +74,7 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.util.BoostFramework;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -92,6 +95,11 @@
static final int POSITION_TOP = Integer.MAX_VALUE;
static final int POSITION_BOTTOM = Integer.MIN_VALUE;
+ public static boolean mPerfSendTapHint = false;
+ public static boolean mIsPerfBoostAcquired = false;
+ public static int mPerfHandle = -1;
+ public BoostFramework mPerfBoost = null;
+ public BoostFramework mUxPerf = null;
/**
* Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
@@ -586,6 +594,39 @@
return someActivityPaused;
}
+ void acquireAppLaunchPerfLock(ActivityRecord r) {
+ /* Acquire perf lock during new app launch */
+ if (mPerfBoost == null) {
+ mPerfBoost = new BoostFramework();
+ }
+ if (mPerfBoost != null) {
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V1);
+ mPerfSendTapHint = true;
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V2);
+
+ if(mPerfBoost.perfGetFeedback(BoostFramework.VENDOR_FEEDBACK_WORKLOAD_TYPE, r.packageName) == BoostFramework.WorkloadType.GAME)
+ {
+ mPerfHandle = mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_GAME);
+ } else {
+ mPerfHandle = mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V3);
+ }
+ if (mPerfHandle > 0)
+ mIsPerfBoostAcquired = true;
+ // Start IOP
+ if(r.info.applicationInfo != null && r.info.applicationInfo.sourceDir != null) {
+ mPerfBoost.perfIOPrefetchStart(-1,r.packageName,
+ r.info.applicationInfo.sourceDir.substring(0, r.info.applicationInfo.sourceDir.lastIndexOf('/')));
+ }
+ }
+ }
+
+ void acquireUxPerfLock(int opcode, String packageName) {
+ mUxPerf = new BoostFramework();
+ if (mUxPerf != null) {
+ mUxPerf.perfUXEngine_events(opcode, 0, packageName, 0);
+ }
+ }
+
/**
* Find task for putting the Activity in.
*/
@@ -609,6 +650,15 @@
// matches not on the specified display.
if (mTmpFindTaskResult.mRecord != null) {
if (mTmpFindTaskResult.mIdealMatch) {
+ if(mTmpFindTaskResult.mRecord.getState() == DESTROYED) {
+ /*It's a new app launch */
+ acquireAppLaunchPerfLock(r);
+ }
+
+ if(mTmpFindTaskResult.mRecord.getState() == STOPPED) {
+ /*Warm launch */
+ acquireUxPerfLock(BoostFramework.UXE_EVENT_SUB_LAUNCH, r.packageName);
+ }
result.setTo(mTmpFindTaskResult);
return;
} else if (isPreferredDisplay) {
@@ -619,6 +669,11 @@
}
}
}
+
+ /* Acquire perf lock *only* during new app launch */
+ if ((mTmpFindTaskResult.mRecord == null) || (mTmpFindTaskResult.mRecord.getState() == DESTROYED)) {
+ acquireAppLaunchPerfLock(r);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 9d41d97..dbcd752 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -78,6 +78,7 @@
import android.os.Message;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.BoostFramework;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -153,6 +154,9 @@
private ArtManagerInternal mArtManagerInternal;
private final StringBuilder mStringBuilder = new StringBuilder();
+ public static BoostFramework mUxPerf = new BoostFramework();
+ private static ActivityRecord mLaunchedActivity;
+
/**
* Due to the global single concurrent launch sequence, all calls to this observer must be made
* in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
@@ -419,7 +423,7 @@
final boolean otherWindowModesLaunching =
mWindowingModeTransitionInfo.size() > 0 && info == null;
- if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
+ if ((!isLoggableResultCode(resultCode) || launchedActivity == null
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
// Failed to launch or it was not a process switch, so we don't care about the timing.
reset(true /* abort */, info, "failed to launch or not a process switch",
@@ -702,6 +706,8 @@
return;
}
+ mLaunchedActivity = info.launchedActivity;
+
// Take a snapshot of the transition info before sending it to the handler for logging.
// This will avoid any races with other operations that modify the ActivityRecord.
final WindowingModeTransitionInfoSnapshot infoSnapshot =
@@ -804,7 +810,22 @@
sb.append(info.launchedActivityShortComponentName);
sb.append(": ");
TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb);
+
+ if (mUxPerf != null) {
+ mUxPerf.perfUXEngine_events(BoostFramework.UXE_EVENT_DISPLAYED_ACT, 0, info.packageName, info.windowsDrawnDelayMs);
+ }
+
Log.i(TAG, sb.toString());
+
+ int isGame = mLaunchedActivity.isAppInfoGame();
+ if (mUxPerf != null) {
+ mUxPerf.perfUXEngine_events(BoostFramework.UXE_EVENT_GAME, 0, info.packageName, isGame);
+ }
+
+ if (mLaunchedActivity.mPerf != null && mLaunchedActivity.perfActivityBoostHandler > 0) {
+ mLaunchedActivity.mPerf.perfLockReleaseHandler(mLaunchedActivity.perfActivityBoostHandler);
+ mLaunchedActivity.perfActivityBoostHandler = -1;
+ }
}
private int convertAppStartTransitionType(int tronType) {
diff --git a/services/core/java/com/android/server/wm/ActivityPluginDelegate.java b/services/core/java/com/android/server/wm/ActivityPluginDelegate.java
new file mode 100644
index 0000000..c0ab0ce
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityPluginDelegate.java
@@ -0,0 +1,174 @@
+/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ *Redistribution and use in source and binary forms, with or without
+ *modification, are permitted provided that the following conditions are
+ *met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.server.wm;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import android.os.Environment;
+import android.util.Log;
+import android.content.Context;
+import android.provider.Settings;
+import android.app.ActivityThread;
+
+public class ActivityPluginDelegate {
+
+ private static final String TAG = "ActivityPluginDelegate";
+ private static final boolean LOGV = false;
+
+ private static Class activityServiceClass = null;
+ private static Object activityServiceObj = null;
+ private static boolean extJarAvail = true;
+
+ private static final String FOREGROUND_ACTIVITY_TRIGGER =
+ "foreground_activity_trigger";
+
+ //Try to get global settings for 15 times, if
+ //foreground_activity_trigger does not set to 1 after 15 times
+ //stop retry and foreground_activity_trigger is 0
+ private static final int MAX_CONNECT_RETRIES = 15;
+
+ static int mGetFeatureEnableRetryCount = MAX_CONNECT_RETRIES;
+ static boolean isEnabled = false;
+
+ public static void activityInvokeNotification(String appName,
+ boolean isFullScreen) {
+ if (LOGV) Log.v(TAG, "activityInvokeNotification("
+ + appName + ", " + isFullScreen + ")");
+ if (!getFeatureFlag() || !extJarAvail || !loadActivityExtJar())
+ return;
+
+ try {
+ activityServiceClass.getMethod("sendActivityInvokeNotification",
+ String.class, boolean.class).invoke(
+ activityServiceObj, appName, isFullScreen);
+ } catch (InvocationTargetException |
+ SecurityException | NoSuchMethodException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to invoke activityInvokeNotification: " + e);
+ e.printStackTrace();
+ }
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "Error calling activityInvokeNotification"+
+ "Method on ActivityExt jar: " + e);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static void activitySuspendNotification(String appName,
+ boolean isFullScreen,
+ boolean isBg) {
+ if (LOGV) Log.v(TAG, "activitySuspendNotification("
+ + appName + ", " + isFullScreen + ", " + isBg + ")");
+ if (!getFeatureFlag() || !extJarAvail || !loadActivityExtJar())
+ return;
+
+ try {
+ activityServiceClass.getMethod("sendActivitySuspendNotification",
+ String.class, boolean.class, boolean.class).invoke(
+ activityServiceObj, appName, isFullScreen, isBg);
+ } catch (InvocationTargetException |
+ SecurityException | NoSuchMethodException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to call sendActivitySuspendNotification: " + e);
+ e.printStackTrace();
+ }
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "Error calling sendActivitySuspendNotification"+
+ "Method on ActivityExt jar: " + e);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static synchronized boolean loadActivityExtJar() {
+ final String realProvider = "com.qualcomm.qti."+
+ "activityextension.ActivityNotifier";
+ final String realProviderPath = Environment.getRootDirectory().
+ getAbsolutePath() + "/framework/ActivityExt.jar";
+
+ if (activityServiceClass != null && activityServiceObj != null) {
+ return true;
+ }
+
+ if ((extJarAvail = new File(realProviderPath).exists()) == false) {
+ if (LOGV) Log.w(TAG, "ActivityExt jar file not present");
+ return extJarAvail;
+ }
+
+ if (activityServiceClass == null && activityServiceObj == null) {
+ if (LOGV) Log.v(TAG, "loading ActivityExt jar");
+ try {
+ PathClassLoader classLoader = new PathClassLoader
+ (realProviderPath, ClassLoader.getSystemClassLoader());
+
+ activityServiceClass = classLoader.loadClass(realProvider);
+ activityServiceObj = activityServiceClass.newInstance();
+ if (LOGV) Log.v(TAG, "ActivityExt jar loaded");
+ } catch (ClassNotFoundException |
+ InstantiationException | IllegalAccessException e) {
+ if (LOGV) {
+ Log.w(TAG, "Failed to find, instantiate or access ActivityExt jar:" + e);
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ return false;
+ } catch (Exception e) {
+ if (LOGV) {
+ Log.w(TAG, "unable to load ActivityExt jar:" + e);
+ e.printStackTrace();
+ }
+ extJarAvail = false;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static synchronized boolean getFeatureFlag() {
+ //Global setting has been enabled for foreground_activity_trigger
+ //Or no one sets foreground_activity_trigger after all retry
+ //No need to invoke Settings API
+ if(isEnabled == true || (mGetFeatureEnableRetryCount == 0)) {
+ return isEnabled;
+ }
+ isEnabled = ((Settings.Global.getInt(ActivityThread.currentApplication().
+ getApplicationContext().getContentResolver(),
+ FOREGROUND_ACTIVITY_TRIGGER, 0)) == 1);
+ --mGetFeatureEnableRetryCount;
+ return isEnabled;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3853841..de6137e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -278,6 +278,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.service.voice.IVoiceInteractionSession;
+import android.util.BoostFramework;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
@@ -339,7 +340,7 @@
/**
* An entry in the history stack, representing an activity.
*/
-final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
+public final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -386,7 +387,7 @@
final int mUserId;
// The package implementing intent's component
// TODO: rename to mPackageName
- final String packageName;
+ public final String packageName;
// the intent component, or target of an alias.
final ComponentName mActivityComponent;
// Has a wallpaper window as a background.
@@ -416,6 +417,7 @@
private int logo; // resource identifier of activity's logo.
private int theme; // resource identifier of activity's theme.
private int windowFlags; // custom window flags for preview window.
+ public int perfActivityBoostHandler = -1; //perflock handler when activity is created.
private TaskRecord task; // the task this is in.
private long createTime = System.currentTimeMillis();
long lastVisibleTime; // last time this activity became visible
@@ -474,6 +476,7 @@
private boolean mLastDeferHidingClient; // If true we will defer setting mClientHidden to true
// and reporting to the client that it is hidden.
boolean sleeping; // have we told the activity to sleep?
+ public boolean launching; // is activity launch in progress?
boolean nowVisible; // is this activity's window visible?
boolean mDrawn; // is this activity's window drawn?
boolean mClientVisibilityDeferred;// was the visibility change message to client deferred?
@@ -523,6 +526,9 @@
boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
IVoiceInteractionSession voiceSession; // Voice interaction session for this activity
+ public BoostFramework mPerf = null;
+ public BoostFramework mPerf_iop = null;
+
boolean mVoiceInteraction;
private int mPendingRelaunchCount;
@@ -1674,6 +1680,9 @@
// Gets launch display id from options. It returns INVALID_DISPLAY if not set.
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
}
+
+ if (mPerf == null)
+ mPerf = new BoostFramework();
}
@Override
@@ -4849,6 +4858,11 @@
if (isActivityTypeHome()) {
mStackSupervisor.updateHomeProcess(task.getChildAt(0).app);
+ try {
+ mStackSupervisor.new PreferredAppsTask().execute();
+ } catch (Exception e) {
+ Slog.v (TAG, "Exception: " + e);
+ }
}
if (nowVisible) {
@@ -4887,6 +4901,7 @@
void stopIfPossible() {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
+ launching = false;
final ActivityStack stack = getActivityStack();
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0) {
@@ -5214,6 +5229,7 @@
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
if (!nowVisible) {
nowVisible = true;
+ launching = false;
lastVisibleTime = SystemClock.uptimeMillis();
mAtmService.scheduleAppGcsLocked();
}
@@ -5224,6 +5240,7 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " + appToken);
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
nowVisible = false;
+ launching = false;
}
@Override
@@ -5808,6 +5825,15 @@
return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
}
+ public int isAppInfoGame() {
+ int isGame = 0;
+ if (info.applicationInfo != null) {
+ isGame = (info.applicationInfo.category == ApplicationInfo.CATEGORY_GAME ||
+ (info.applicationInfo.flags & ApplicationInfo.FLAG_IS_GAME) == ApplicationInfo.FLAG_IS_GAME) ? 1 : 0;
+ }
+ return isGame;
+ }
+
/**
* Creates a layer to apply crop to an animation.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 41c1e4e..8589669 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -145,6 +145,8 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import com.android.internal.app.ActivityTrigger;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -153,6 +155,7 @@
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
+import android.util.BoostFramework;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.EventLogTags;
@@ -166,7 +169,7 @@
/**
* State and management of a single stack of activities.
*/
-class ActivityStack extends ConfigurationContainer {
+public class ActivityStack extends ConfigurationContainer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -305,6 +308,7 @@
final ActivityTaskManagerService mService;
final WindowManagerService mWindowManager;
+ public BoostFramework mPerf = null;
/**
* The back history of all previous (and possibly still
* running) activities. It contains #TaskRecord objects.
@@ -418,8 +422,12 @@
private final Handler mHandler;
- private class ActivityStackHandler extends Handler {
+ static final ActivityTrigger mActivityTrigger = new ActivityTrigger();
+ private static final ActivityPluginDelegate mActivityPluginDelegate =
+ new ActivityPluginDelegate();
+
+ private class ActivityStackHandler extends Handler {
ActivityStackHandler(Looper looper) {
super(looper);
}
@@ -1053,7 +1061,7 @@
return super.setBounds(!inMultiWindowMode() ? null : bounds);
}
- ActivityRecord topRunningActivityLocked() {
+ public ActivityRecord topRunningActivityLocked() {
return topRunningActivityLocked(false /* focusableOnly */);
}
@@ -1651,6 +1659,15 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
+
+ if (mActivityTrigger != null) {
+ mActivityTrigger.activityPauseTrigger(prev.intent, prev.info, prev.info.applicationInfo);
+ }
+
+ if (mActivityPluginDelegate != null && getWindowingMode() != WINDOWING_MODE_UNDEFINED) {
+ mActivityPluginDelegate.activitySuspendNotification
+ (prev.info.applicationInfo.packageName, getWindowingMode() == WINDOWING_MODE_FULLSCREEN, true);
+ }
mPausingActivity = prev;
mLastPausedActivity = prev;
mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
@@ -2590,9 +2607,20 @@
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
+ next.launching = true;
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
+ if (mActivityTrigger != null) {
+ mActivityTrigger.activityResumeTrigger(next.intent, next.info, next.info.applicationInfo,
+ next.occludesParent());
+ }
+
+ if (mActivityPluginDelegate != null && getWindowingMode() != WINDOWING_MODE_UNDEFINED) {
+ mActivityPluginDelegate.activityInvokeNotification
+ (next.info.applicationInfo.packageName, getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
+ }
+
// If we are currently pausing an activity, then don't do anything until that is done.
if (!mRootActivityContainer.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
@@ -2709,6 +2737,9 @@
// to ignore it when computing the desired screen orientation.
boolean anim = true;
final DisplayContent dc = display.mDisplayContent;
+ if (mPerf == null) {
+ mPerf = new BoostFramework();
+ }
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
@@ -2717,6 +2748,12 @@
anim = false;
dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
+ mWindowManager.prepareAppTransition(prev.getTaskRecord() == next.getTaskRecord()
+ ? TRANSIT_ACTIVITY_CLOSE
+ : TRANSIT_TASK_CLOSE, false);
+ if(prev.getTaskRecord() != next.getTaskRecord() && mPerf != null) {
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_ANIM_BOOST, next.packageName);
+ }
dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
@@ -2729,6 +2766,14 @@
anim = false;
dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
+ mWindowManager.prepareAppTransition(prev.getTaskRecord() == next.getTaskRecord()
+ ? TRANSIT_ACTIVITY_OPEN
+ : next.mLaunchTaskBehind
+ ? TRANSIT_TASK_OPEN_BEHIND
+ : TRANSIT_TASK_OPEN, false);
+ if(prev.getTaskRecord() != next.getTaskRecord() && mPerf != null) {
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_ANIM_BOOST, next.packageName);
+ }
dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
@@ -3075,6 +3120,11 @@
new RuntimeException("here").fillInStackTrace());
r.setTask(task);
+ if (mActivityPluginDelegate != null) {
+ mActivityPluginDelegate.activityInvokeNotification
+ (r.info.applicationInfo.packageName, r.occludesParent());
+ }
+
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 887ece5..06c17d3 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -52,6 +52,7 @@
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
@@ -130,6 +131,8 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.BoostFramework;
+import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -149,6 +152,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Arrays;
+import android.os.AsyncTask;
+
// TODO: This class has become a dumping ground. Let's
// - Move things relating to the hierarchy to RootWindowContainer
// - Move things relating to activity life cycles to maybe a new class called ActivityLifeCycler
@@ -180,6 +186,13 @@
static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
+
+ public static boolean mPerfSendTapHint = false;
+ public static boolean mIsPerfBoostAcquired = false;
+ public static int mPerfHandle = -1;
+ public BoostFramework mPerfBoost = new BoostFramework();
+ public BoostFramework mUxPerf = new BoostFramework();
+
static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
@@ -241,7 +254,7 @@
private static final int MAX_TASK_IDS_PER_USER = UserHandle.PER_USER_RANGE;
final ActivityTaskManagerService mService;
- RootActivityContainer mRootActivityContainer;
+ public RootActivityContainer mRootActivityContainer;
/** The historial list of recent tasks including inactive tasks */
RecentTasks mRecentTasks;
@@ -626,6 +639,13 @@
void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime,
@WaitResult.LaunchState int launchState) {
boolean changed = false;
+ if (totalTime > 0) {
+ if (mPerfBoost != null) {
+ if (r.app != null) {
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_DRAW, r.packageName, r.app.getPid(), BoostFramework.Draw.EVENT_TYPE_V1);
+ }
+ }
+ }
for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
WaitResult w = mWaitingActivityLaunched.remove(i);
if (w.who == null) {
@@ -715,7 +735,7 @@
}
}
- ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
+ public ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
ProfilerInfo profilerInfo, int userId, int filterCallingUid) {
final ResolveInfo rInfo = resolveIntent(intent, resolvedType, userId, 0, filterCallingUid);
return resolveActivity(intent, rInfo, startFlags, profilerInfo);
@@ -980,6 +1000,10 @@
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
+ if (mPerfBoost != null) {
+ Slog.i(TAG, "The Process " + r.processName + " Already Exists in BG. So sending its PID: " + wpc.getPid());
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.processName, wpc.getPid(), BoostFramework.Launch.TYPE_START_APP_FROM_BG);
+ }
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
@@ -1386,6 +1410,16 @@
void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason,
boolean forceNonResizeable) {
ActivityStack currentStack = task.getStack();
+
+ ActivityStack focusedStack = mRootActivityContainer.getTopDisplayFocusedStack();
+ ActivityRecord top_activity = focusedStack != null ? focusedStack.getTopActivity() : null;
+
+ //top_activity = task.stack.topRunningActivityLocked();
+ /* App is launching from recent apps and it's a new process */
+ if((top_activity != null) && (top_activity.getState() == DESTROYED)) {
+ acquireAppLaunchPerfLock(top_activity);
+ }
+
if (currentStack == null) {
Slog.e(TAG, "findTaskToMoveToFront: can't move task="
+ task + " to front. Stack is null");
@@ -1872,6 +1906,15 @@
ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
procsToKill);
mService.mH.sendMessage(m);
+
+ if(removeFromRecents) {
+ try {
+ new PreferredAppsTask().execute();
+ } catch (Exception e) {
+ Slog.v (TAG, "Exception: " + e);
+ }
+ }
+
}
/**
@@ -2025,6 +2068,29 @@
return timedout;
}
+ void acquireAppLaunchPerfLock(ActivityRecord r) {
+ /* Acquire perf lock during new app launch */
+ if (mPerfBoost != null) {
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V1);
+ mPerfSendTapHint = true;
+ mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V2);
+
+ if(mPerfBoost.perfGetFeedback(BoostFramework.VENDOR_FEEDBACK_WORKLOAD_TYPE, r.packageName) == BoostFramework.WorkloadType.GAME)
+ {
+ mPerfHandle = mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_GAME);
+ } else {
+ mPerfHandle = mPerfBoost.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, r.packageName, -1, BoostFramework.Launch.BOOST_V3);
+ }
+ if (mPerfHandle > 0)
+ mIsPerfBoostAcquired = true;
+ // Start IOP
+ if (r.info.applicationInfo != null && r.info.applicationInfo.sourceDir != null) {
+ mPerfBoost.perfIOPrefetchStart(-1,r.packageName,
+ r.info.applicationInfo.sourceDir.substring(0, r.info.applicationInfo.sourceDir.lastIndexOf('/')));
+ }
+ }
+ }
+
void comeOutOfSleepIfNeededLocked() {
removeSleepTimeouts();
if (mGoingToSleepWakeLock.isHeld()) {
@@ -2862,4 +2928,37 @@
mResult.dump(pw, prefix);
}
}
+
+ class PreferredAppsTask extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected Void doInBackground(Void... params) {
+ String res = null;
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ int trimLevel = 0;
+ try {
+ trimLevel = ActivityManager.getService().getMemoryTrimLevel();
+ } catch (RemoteException e) {
+ return null;
+ }
+ if (mUxPerf != null
+ && trimLevel < ProcessStats.ADJ_MEM_FACTOR_CRITICAL) {
+ res = mUxPerf.perfUXEngine_trigger(BoostFramework.UXE_TRIGGER);
+ if (res == null)
+ return null;
+ String[] p_apps = res.split("/");
+ if (p_apps.length != 0) {
+ ArrayList<String> apps_l = new ArrayList(Arrays.asList(p_apps));
+ Bundle bParams = new Bundle();
+ if (bParams == null)
+ return null;
+ bParams.putStringArrayList("start_empty_apps", apps_l);
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::startActivityAsUserEmpty, mService.mAmInternal, bParams);
+ mService.mH.sendMessage(msg);
+ }
+ }
+ return null;
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2ac681c..174d8b3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -113,6 +113,7 @@
import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
+import android.util.BoostFramework;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pools.SynchronizedPool;
@@ -198,6 +199,8 @@
private IVoiceInteractionSession mVoiceSession;
private IVoiceInteractor mVoiceInteractor;
+ public BoostFramework mPerf = null;
+
// Last activity record we attempted to start
private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
// The result of the last activity we attempted to start.
@@ -445,6 +448,7 @@
mSupervisor = supervisor;
mInterceptor = interceptor;
reset(true);
+ mPerf = new BoostFramework();
}
/**
@@ -1548,6 +1552,12 @@
if (newTask) {
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTaskRecord() : null;
+ String packageName= mService.mContext.getPackageName();
+ if (mPerf != null) {
+ mStartActivity.perfActivityBoostHandler =
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST,
+ packageName, -1, BoostFramework.Launch.BOOST_V1);
+ }
setNewTask(taskToAffiliate);
if (mService.getLockTaskController().isLockTaskModeViolation(
mStartActivity.getTaskRecord())) {
@@ -2449,6 +2459,12 @@
}
private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
+ String packageName= mService.mContext.getPackageName();
+ if (mPerf != null) {
+ mStartActivity.perfActivityBoostHandler =
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST,
+ packageName, -1, BoostFramework.Launch.BOOST_V1);
+ }
if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
parent.addActivityToTop(mStartActivity);
} else {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 14df505..946e42c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -370,7 +370,7 @@
* @see WindowManagerThreadPriorityBooster
*/
final Object mGlobalLockWithoutBoost = mGlobalLock;
- ActivityStackSupervisor mStackSupervisor;
+ public ActivityStackSupervisor mStackSupervisor;
RootActivityContainer mRootActivityContainer;
WindowManagerService mWindowManager;
private UserManagerService mUserManager;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index a783ee9..2400a33 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -17,11 +17,13 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.TYPE_BUILT_IN;
@@ -120,6 +122,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.pm.ApplicationInfo;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -132,6 +135,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.util.BoostFramework;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
@@ -234,6 +238,18 @@
private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
private final ScreenshotHelper mScreenshotHelper;
+ private static boolean SCROLL_BOOST_SS_ENABLE = false;
+ private static boolean isLowRAM = false;
+
+ /*
+ * @hide
+ */
+ BoostFramework mPerfBoostDrag = null;
+ BoostFramework mPerfBoostFling = null;
+ BoostFramework mPerfBoostPrefling = null;
+ BoostFramework mPerf = new BoostFramework();
+ private boolean mIsPerfBoostFlingAcquired;
+
private final Object mServiceAcquireLock = new Object();
private StatusBarManagerInternal mStatusBarManagerInternal;
@@ -438,6 +454,38 @@
}
}
+ private String getAppPackageName() {
+ String currentPackage;
+ try {
+ ActivityManager.RunningTaskInfo rti = ActivityManager.getService().getFilteredTasks(1,
+ ACTIVITY_TYPE_RECENTS, WINDOWING_MODE_UNDEFINED).get(0);
+ currentPackage = rti.topActivity.getPackageName();
+ } catch (Exception e) {
+ currentPackage = null;
+ }
+ return currentPackage;
+ }
+
+ private boolean isTopAppGame(String currentPackage, BoostFramework BoostType) {
+ boolean isGame = false;
+ if (isLowRAM) {
+ try {
+ ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(currentPackage, 0);
+ if(ai != null) {
+ isGame = (ai.category == ApplicationInfo.CATEGORY_GAME) ||
+ ((ai.flags & ApplicationInfo.FLAG_IS_GAME) ==
+ ApplicationInfo.FLAG_IS_GAME);
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ } else {
+ isGame = (BoostType.perfGetFeedback(BoostFramework.VENDOR_FEEDBACK_WORKLOAD_TYPE,
+ currentPackage) == BoostFramework.WorkloadType.GAME);
+ }
+ return isGame;
+ }
+
DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mContext = displayContent.isDefaultDisplay ? service.mContext
@@ -469,6 +517,10 @@
mScreenOnFully = true;
}
+ if (mPerf != null)
+ SCROLL_BOOST_SS_ENABLE = Boolean.parseBoolean(mPerf.perfGetProp("vendor.perf.gestureflingboost.enable", "false"));
+ isLowRAM = SystemProperties.getBoolean("ro.config.low_ram", false);
+
final Looper looper = UiThread.getHandler().getLooper();
mHandler = new PolicyHandler(looper);
mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
@@ -528,6 +580,94 @@
}
@Override
+ public void onVerticalFling(int duration) {
+ String currentPackage = getAppPackageName();
+ if (currentPackage == null) {
+ Slog.e(TAG, "Error: package name null");
+ return;
+ }
+ if (SCROLL_BOOST_SS_ENABLE) {
+ if (mPerfBoostFling == null) {
+ mPerfBoostFling = new BoostFramework();
+ mIsPerfBoostFlingAcquired = false;
+ }
+ if (mPerfBoostFling == null) {
+ Slog.e(TAG, "Error: boost object null");
+ return;
+ }
+ boolean isGame = isTopAppGame(currentPackage, mPerfBoostFling);
+ if (!isGame) {
+ mPerfBoostFling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
+ currentPackage, duration + 160, BoostFramework.Scroll.VERTICAL);
+ mIsPerfBoostFlingAcquired = true;
+ }
+ }
+ }
+
+ @Override
+ public void onHorizontalFling(int duration) {
+ String currentPackage = getAppPackageName();
+ if (currentPackage == null) {
+ Slog.e(TAG, "Error: package name null");
+ return;
+ }
+ if (SCROLL_BOOST_SS_ENABLE) {
+ if (mPerfBoostFling == null) {
+ mPerfBoostFling = new BoostFramework();
+ mIsPerfBoostFlingAcquired = false;
+ }
+ if (mPerfBoostFling == null) {
+ Slog.e(TAG, "Error: boost object null");
+ return;
+ }
+ boolean isGame = isTopAppGame(currentPackage, mPerfBoostFling);
+ if (!isGame) {
+ mPerfBoostFling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
+ currentPackage, duration + 160, BoostFramework.Scroll.HORIZONTAL);
+ mIsPerfBoostFlingAcquired = true;
+ }
+ }
+ }
+
+ @Override
+ public void onScroll(boolean started) {
+ String currentPackage = getAppPackageName();
+ if (currentPackage == null) {
+ Slog.e(TAG, "Error: package name null");
+ return;
+ }
+ boolean isGame;
+ if (mPerfBoostDrag == null) {
+ mPerfBoostDrag = new BoostFramework();
+ }
+ if (mPerfBoostDrag == null) {
+ Slog.e(TAG, "Error: boost object null");
+ return;
+ }
+ if (SCROLL_BOOST_SS_ENABLE) {
+ if (mPerfBoostPrefling == null) {
+ mPerfBoostPrefling = new BoostFramework();
+ }
+ if (mPerfBoostPrefling == null) {
+ Slog.e(TAG, "Error: boost object null");
+ return;
+ }
+ isGame = isTopAppGame(currentPackage, mPerfBoostPrefling);
+ if (!isGame) {
+ mPerfBoostPrefling.perfHint(BoostFramework.VENDOR_HINT_SCROLL_BOOST,
+ currentPackage, -1, BoostFramework.Scroll.PREFILING);
+ }
+ }
+ isGame = isTopAppGame(currentPackage, mPerfBoostDrag);
+ if (!isGame && started) {
+ mPerfBoostDrag.perfHint(BoostFramework.VENDOR_HINT_DRAG_BOOST,
+ currentPackage, -1, 1);
+ } else {
+ mPerfBoostDrag.perfLockRelease();
+ }
+ }
+
+ @Override
public void onDebug() {
// no-op
}
@@ -543,6 +683,11 @@
if (listener != null) {
listener.onTouchStart();
}
+ if(SCROLL_BOOST_SS_ENABLE && mPerfBoostFling!= null
+ && mIsPerfBoostFlingAcquired) {
+ mPerfBoostFling.perfLockRelease();
+ mIsPerfBoostFlingAcquired = false;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 67f1d1b..10a6d0c 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -34,9 +34,11 @@
import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.pm.PackageManager;
@@ -212,6 +214,24 @@
private boolean mDemoHdmiRotationLock;
private boolean mDemoRotationLock;
+ /**
+ * Broadcast Action: WiFi Display video is enabled or disabled
+ *
+ * <p>The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>state</em> - 0 for disabled, 1 for enabled. </li>
+ * </ul>
+ */
+
+ private static final String ACTION_WIFI_DISPLAY_VIDEO =
+ "org.codeaurora.intent.action.WIFI_DISPLAY_VIDEO";
+
+ /**
+ * Wifi Display specific variables
+ */
+ private boolean mWifiDisplayConnected = false;
+ private int mWifiDisplayRotation = -1;
+
DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
this(service, displayContent, displayContent.getDisplayPolicy(),
service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
@@ -243,6 +263,46 @@
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
}
+ /* Register for WIFI Display Intents in a separate thread
+ * to avoid possible deadlock between ActivityManager and
+ * WindowManager global locks*/
+ Thread t = new Thread(){
+ public void run() {
+ context.registerReceiver(new BroadcastReceiver(){
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_WIFI_DISPLAY_VIDEO)) {
+ int state = intent.getIntExtra("state", 0);
+ if(state == 1) {
+ mWifiDisplayConnected = true;
+ } else {
+ mWifiDisplayConnected = false;
+ }
+ int rotation = intent.getIntExtra("wfd_UIBC_rot", -1);
+ switch (rotation) {
+ case 0:
+ mWifiDisplayRotation = Surface.ROTATION_0;
+ break;
+ case 1:
+ mWifiDisplayRotation = Surface.ROTATION_90;
+ break;
+ case 2:
+ mWifiDisplayRotation = Surface.ROTATION_180;
+ break;
+ case 3:
+ mWifiDisplayRotation = Surface.ROTATION_270;
+ break;
+ default:
+ mWifiDisplayRotation = -1;
+ }
+ mService.updateRotation(true /* alwaysSendConfiguration */,
+ false/* forceRelayout */);
+ }
+ }
+ }, new IntentFilter(ACTION_WIFI_DISPLAY_VIDEO), null, UiThread.getHandler());
+ }
+ };
+ t.start();
}
private int readRotation(int resID) {
@@ -1000,10 +1060,13 @@
// This case can override the behavior of NOSENSOR, and can also
// enable 180 degree rotation while docked.
preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
- } else if (hdmiPlugged && mDemoHdmiRotationLock) {
+ } else if ((hdmiPlugged || mWifiDisplayConnected) && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
+ } else if (mWifiDisplayConnected && (mWifiDisplayRotation > -1)) {
+ // Ignore sensor when WFD is active and UIBC rotation is enabled
+ preferredRotation = mWifiDisplayRotation;
} else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
&& mUndockedHdmiRotation >= 0) {
// Ignore sensor when plugged into HDMI and an undocked orientation has
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 7169677..4e95d11 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -67,6 +67,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.BoostFramework;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -192,6 +193,7 @@
private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
+ private final BoostFramework mUxPerf = new BoostFramework();
// TODO(b/127498985): This is currently a rough heuristic for interaction inside an app
private final PointerEventListener mListener = new PointerEventListener() {
@@ -1171,6 +1173,13 @@
void remove(TaskRecord task) {
mTasks.remove(task);
notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
+ if (task != null) {
+ final String taskPkgName =
+ task.getBaseIntent().getComponent().getPackageName();
+ if (mUxPerf != null) {
+ mUxPerf.perfUXEngine_events(BoostFramework.UXE_EVENT_KILL, 0, taskPkgName, 0);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 9db6dc2..999d576 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -129,7 +129,7 @@
* TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The
* intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.
*/
-class RootActivityContainer extends ConfigurationContainer
+public class RootActivityContainer extends ConfigurationContainer
implements DisplayManager.DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "RootActivityContainer" : TAG_ATM;
@@ -690,7 +690,7 @@
return topActivityTokens;
}
- ActivityStack getTopDisplayFocusedStack() {
+ public ActivityStack getTopDisplayFocusedStack() {
for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
final ActivityStack focusedStack = mActivityDisplays.get(i).getFocusedStack();
if (focusedStack != null) {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 157bd3b..b4467f9 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -83,6 +83,8 @@
private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
+ private boolean mIsPerfLockAcquired = false;
+
private final Context mContext;
private final DisplayContent mDisplayContent;
private final float[] mTmpFloats = new float[9];
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index fb781b0..6842b3b 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -69,6 +69,7 @@
private boolean mDebugFireable;
private boolean mMouseHoveringAtEdge;
private long mLastFlingTime;
+ private boolean mScrollFired;
SystemGesturesPointerEventListener(Context context, Handler handler, Callbacks callbacks) {
mContext = checkNull("context", context);
@@ -130,6 +131,7 @@
case MotionEvent.ACTION_DOWN:
mSwipeFireable = true;
mDebugFireable = true;
+ mScrollFired = false;
mDownPointers = 0;
captureDown(event, 0);
if (mMouseHoveringAtEdge) {
@@ -186,6 +188,9 @@
case MotionEvent.ACTION_CANCEL:
mSwipeFireable = false;
mDebugFireable = false;
+ if (mScrollFired)
+ mCallbacks.onScroll(false);
+ mScrollFired = false;
mCallbacks.onUpOrCancel();
break;
default:
@@ -308,10 +313,25 @@
if (duration > MAX_FLING_TIME_MILLIS) {
duration = MAX_FLING_TIME_MILLIS;
}
+ if(Math.abs(velocityY) >= Math.abs(velocityX))
+ mCallbacks.onVerticalFling(duration);
+ else
+ mCallbacks.onHorizontalFling(duration);
+
mLastFlingTime = now;
mCallbacks.onFling(duration);
return true;
}
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ if (!mScrollFired) {
+ mCallbacks.onScroll(true);
+ mScrollFired = true;
+ }
+ return true;
+ }
}
interface Callbacks {
@@ -320,6 +340,9 @@
void onSwipeFromRight();
void onSwipeFromLeft();
void onFling(int durationMs);
+ void onVerticalFling(int durationMs);
+ void onHorizontalFling(int durationMs);
+ void onScroll(boolean started);
void onDown();
void onUpOrCancel();
void onMouseHoverAtTop();
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 79baab6..f11335e 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -29,6 +29,10 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.server.wm.WindowManagerService.H;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.wm.ActivityStackSupervisor;
+import com.android.server.wm.ActivityDisplay;
+import android.util.BoostFramework;
/**
* 1. Adjust the top most focus display if touch down on some display.
@@ -41,11 +45,15 @@
private final DisplayContent mDisplayContent;
private final Rect mTmpRect = new Rect();
private int mPointerIconType = TYPE_NOT_SPECIFIED;
+ public BoostFramework mPerfObj = null;
public TaskTapPointerEventListener(WindowManagerService service,
DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
+ if (mPerfObj == null) {
+ mPerfObj = new BoostFramework();
+ }
}
@Override
@@ -113,6 +121,28 @@
}
break;
}
+ if (ActivityStackSupervisor.mIsPerfBoostAcquired && (mPerfObj != null)) {
+ if (ActivityStackSupervisor.mPerfHandle > 0) {
+ mPerfObj.perfLockReleaseHandler(ActivityStackSupervisor.mPerfHandle);
+ ActivityStackSupervisor.mPerfHandle = -1;
+ }
+ ActivityStackSupervisor.mIsPerfBoostAcquired = false;
+ }
+ if (ActivityStackSupervisor.mPerfSendTapHint && (mPerfObj != null)) {
+ mPerfObj.perfHint(BoostFramework.VENDOR_HINT_TAP_EVENT, null);
+ ActivityStackSupervisor.mPerfSendTapHint = false;
+ }
+ if (ActivityDisplay.mIsPerfBoostAcquired && (mPerfObj != null)) {
+ if (ActivityDisplay.mPerfHandle > 0) {
+ mPerfObj.perfLockReleaseHandler(ActivityDisplay.mPerfHandle);
+ ActivityDisplay.mPerfHandle = -1;
+ }
+ ActivityDisplay.mIsPerfBoostAcquired = false;
+ }
+ if (ActivityDisplay.mPerfSendTapHint && (mPerfObj != null)) {
+ mPerfObj.perfHint(BoostFramework.VENDOR_HINT_TAP_EVENT, null);
+ ActivityDisplay.mPerfSendTapHint = false;
+ }
}
void setTouchExcludeRegion(Region newRegion) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 63ce1b1..5fbad4a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -190,6 +190,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.BoostFramework;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -305,7 +306,8 @@
static final int LAYOUT_REPEAT_THRESHOLD = 4;
static final boolean PROFILE_ORIENTATION = false;
-
+ static WindowState mFocusingWindow;
+ String mFocusingActivity;
/** How much to multiply the policy's type layer, to reserve room
* for multiple windows of the same type and Z-ordering adjustment
* with TYPE_LAYER_OFFSET. */
@@ -406,6 +408,8 @@
final WindowTracing mWindowTracing;
+ private BoostFramework mPerf = null;
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
// TODO: eventually unify all keyguard state in a common place instead of having it spread over
// AM's KeyguardController and the policy's KeyguardServiceDelegate.
@@ -3033,12 +3037,28 @@
ValueAnimator.setDurationScale(scale);
}
+ private float animationScalesCheck (int which) {
+ float value = -1.0f;
+ if (!mAnimationsDisabled) {
+ if (value == -1.0f) {
+ switch (which) {
+ case WINDOW_ANIMATION_SCALE: value = mWindowAnimationScaleSetting; break;
+ case TRANSITION_ANIMATION_SCALE: value = mTransitionAnimationScaleSetting; break;
+ case ANIMATION_DURATION_SCALE: value = mAnimatorDurationScaleSetting; break;
+ }
+ }
+ } else {
+ value = 0;
+ }
+ return value;
+ }
+
public float getWindowAnimationScaleLocked() {
- return mAnimationsDisabled ? 0 : mWindowAnimationScaleSetting;
+ return animationScalesCheck(WINDOW_ANIMATION_SCALE);
}
public float getTransitionAnimationScaleLocked() {
- return mAnimationsDisabled ? 0 : mTransitionAnimationScaleSetting;
+ return animationScalesCheck(TRANSITION_ANIMATION_SCALE);
}
@Override
@@ -5353,6 +5373,12 @@
}
mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
+ if (mPerf == null) {
+ mPerf = new BoostFramework();
+ }
+ if (mPerf != null) {
+ mPerf.perfHint(BoostFramework.VENDOR_HINT_ROTATION_LATENCY_BOOST, null);
+ }
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
ScreenRotationAnimation screenRotationAnimation =
@@ -5473,6 +5499,9 @@
displayContent.sendNewConfiguration();
}
mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN);
+ if (mPerf != null) {
+ mPerf.perfLockRelease();
+ }
}
static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5883048..9f9ff4f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -50,6 +50,7 @@
import android.os.FactoryTest;
import android.os.FileUtils;
import android.os.IIncidentManager;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -162,6 +163,9 @@
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
+import dalvik.system.PathClassLoader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import com.google.android.startop.iorap.IorapForwardingService;
@@ -916,6 +920,8 @@
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
+ Object wigigP2pService = null;
+ Object wigigService = null;
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
@@ -927,6 +933,7 @@
boolean enableLeftyService = SystemProperties.getBoolean("config.enable_lefty", false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
+ boolean enableWigig = SystemProperties.getBoolean("persist.vendor.wigig.enable", false);
boolean isWatch = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WATCH);
@@ -1389,6 +1396,34 @@
}
t.traceEnd();
+ if (enableWigig) {
+ try {
+ Slog.i(TAG, "Wigig Service");
+ String wigigClassPath =
+ "/system/framework/wigig-service.jar" + ":" +
+ "/system/product/framework/vendor.qti.hardware.wigig.supptunnel-V1.0-java.jar" + ":" +
+ "/system/product/framework/vendor.qti.hardware.wigig.netperftuner-V1.0-java.jar" + ":" +
+ "/system/product/framework/vendor.qti.hardware.capabilityconfigstore-V1.0-java.jar";
+ PathClassLoader wigigClassLoader =
+ new PathClassLoader(wigigClassPath, getClass().getClassLoader());
+ Class wigigP2pClass = wigigClassLoader.loadClass(
+ "com.qualcomm.qti.server.wigig.p2p.WigigP2pServiceImpl");
+ Constructor<Class> ctor = wigigP2pClass.getConstructor(Context.class);
+ wigigP2pService = ctor.newInstance(context);
+ Slog.i(TAG, "Successfully loaded WigigP2pServiceImpl class");
+ ServiceManager.addService("wigigp2p", (IBinder) wigigP2pService);
+
+ Class wigigClass = wigigClassLoader.loadClass(
+ "com.qualcomm.qti.server.wigig.WigigService");
+ ctor = wigigClass.getConstructor(Context.class);
+ wigigService = ctor.newInstance(context);
+ Slog.i(TAG, "Successfully loaded WigigService class");
+ ServiceManager.addService("wigig", (IBinder) wigigService);
+ } catch (Throwable e) {
+ reportWtf("starting WigigService", e);
+ }
+ }
+
t.traceBegin("StartNsdService");
try {
serviceDiscovery = NsdService.create(context);
@@ -1939,6 +1974,25 @@
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_SYSTEM_SERVICES_READY);
t.traceEnd();
+ // Wigig services are not registered as system services because of class loader
+ // limitations, send boot phase notification separately
+ if (enableWigig) {
+ try {
+ Slog.i(TAG, "calling onBootPhase for Wigig Services");
+ Class wigigP2pClass = wigigP2pService.getClass();
+ Method m = wigigP2pClass.getMethod("onBootPhase", int.class);
+ m.invoke(wigigP2pService, new Integer(
+ SystemService.PHASE_SYSTEM_SERVICES_READY));
+
+ Class wigigClass = wigigService.getClass();
+ m = wigigClass.getMethod("onBootPhase", int.class);
+ m.invoke(wigigService, new Integer(
+ SystemService.PHASE_SYSTEM_SERVICES_READY));
+ } catch (Throwable e) {
+ reportWtf("Wigig services ready", e);
+ }
+ }
+
t.traceBegin("MakeWindowManagerServiceReady");
try {
wm.systemReady();
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 3d79bba..33984bf 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -95,6 +95,8 @@
private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
+ private static final String WIGIG_HOST_IFACE_ADDR = "192.168.50.1";
+ private static final int WIGIG_HOST_IFACE_PREFIX_LENGTH = 24;
// TODO: have PanService use some visible version of this constant
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
@@ -244,6 +246,7 @@
setInitialState(mInitialState);
}
+
public String interfaceName() { return mIfaceName; }
public int interfaceType() { return mInterfaceType; }
@@ -408,6 +411,9 @@
} else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) {
ipAsString = WIFI_P2P_IFACE_ADDR;
prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
+ } else if (mInterfaceType == ConnectivityManager.TETHERING_WIGIG) {
+ ipAsString = WIGIG_HOST_IFACE_ADDR;
+ prefixLen = WIGIG_HOST_IFACE_PREFIX_LENGTH;
} else {
// BT configures the interface elsewhere: only start DHCP.
final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
@@ -425,7 +431,8 @@
InetAddress addr = numericToInetAddress(ipAsString);
linkAddr = new LinkAddress(addr, prefixLen);
ifcg.setLinkAddress(linkAddr);
- if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
+ if (mInterfaceType == ConnectivityManager.TETHERING_WIFI ||
+ mInterfaceType == ConnectivityManager.TETHERING_WIGIG) {
// The WiFi stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own
// state.
diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java
index 6f9c294..8b4c25b 100644
--- a/services/net/java/android/net/shared/ProvisioningConfiguration.java
+++ b/services/net/java/android/net/shared/ProvisioningConfiguration.java
@@ -202,6 +202,8 @@
public ApfCapabilities mApfCapabilities;
public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+ public boolean mRapidCommit;
+ public boolean mDiscoverSent;
public Network mNetwork = null;
public String mDisplayName = null;
@@ -219,6 +221,8 @@
: new StaticIpConfiguration(other.mStaticIpConfig);
mApfCapabilities = other.mApfCapabilities;
mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
+ mRapidCommit = other.mRapidCommit;
+ mDiscoverSent = other.mDiscoverSent;
mIPv6AddrGenMode = other.mIPv6AddrGenMode;
mNetwork = other.mNetwork;
mDisplayName = other.mDisplayName;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 8a9423a..b9d4c31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -82,6 +82,7 @@
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
+import org.junit.Ignore;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -390,6 +391,7 @@
* Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
* when we are laying out a new task.
*/
+ @Ignore // TODO(b/119048275): Reenable failing test in activity_manager_test suite
@Test
public void testCreateTaskLayout() {
// modifier for validating passed values.
@@ -494,6 +496,7 @@
/**
* Tests activity is cleaned up properly in a task mode violation.
*/
+ @Ignore // TODO(b/119048275): Reenable failing test in activity_manager_test suite
@Test
public void testTaskModeViolation() {
final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
@@ -521,6 +524,7 @@
/**
* This test ensures that activity starts are not being logged when the logging is disabled.
*/
+ @Ignore // TODO(b/119048275): Reenable failing test in activity_manager_test suite
@Test
public void testActivityStartsLogging_noLoggingWhenDisabled() {
doReturn(false).when(mService).isActivityStartsLoggingEnabled();
@@ -537,6 +541,7 @@
/**
* This test ensures that activity starts are being logged when the logging is enabled.
*/
+ @Ignore // TODO(b/119048275): Reenable failing test in activity_manager_test suite
@Test
public void testActivityStartsLogging_logsWhenEnabled() {
// note: conveniently this package doesn't have any activity visible
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
old mode 100644
new mode 100755
index 9f3b07b..6bda938
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -129,6 +129,8 @@
private static final String USB_STATE_MATCH =
"DEVPATH=/devices/virtual/android_usb/android0";
+ private static final String USB_STATE_MATCH_SEC =
+ "DEVPATH=/devices/virtual/android_usb/android1";
private static final String ACCESSORY_START_MATCH =
"DEVPATH=/devices/virtual/misc/usb_accessory";
private static final String FUNCTIONS_PATH =
@@ -353,6 +355,7 @@
// Watch for USB configuration changes
mUEventObserver = new UsbUEventObserver();
mUEventObserver.startObserving(USB_STATE_MATCH);
+ mUEventObserver.startObserving(USB_STATE_MATCH_SEC);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
}
@@ -1559,6 +1562,10 @@
mCurrentFunctions = usbFunctions;
if (functions == null || applyAdbFunction(functions)
.equals(UsbManager.USB_FUNCTION_NONE)) {
+ functions = getSystemProperty(getPersistProp(true),
+ UsbManager.USB_FUNCTION_NONE);
+
+ if (functions.equals(UsbManager.USB_FUNCTION_NONE))
functions = UsbManager.usbFunctionsToString(getChargingFunctions());
}
functions = applyAdbFunction(functions);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 60290e3..f1fe5b1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -431,11 +431,24 @@
*/
public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
+ /**
+ * Add participant in an active or conference call option
+ * @hide
+ */
+ public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+
/** Call supports the deflect feature. */
public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000;
+ /**
+ * Remote device supports RTT.
+ * @hide
+ */
+
+ public static final int CAPABILITY_SUPPORTS_RTT_REMOTE = 0x04000000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x02000000
+ // Next CAPABILITY value: 0x08000000
//******************************************************************************************
/**
@@ -653,9 +666,15 @@
if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
builder.append(" CAPABILITY_CAN_PULL_CALL");
}
+ if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
+ builder.append(" CAPABILITY_ADD_PARTICIPANT");
+ }
if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
builder.append(" CAPABILITY_SUPPORT_DEFLECT");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_RTT_REMOTE)) {
+ builder.append(" CAPABILITY_SUPPORTS_RTT_REMOTE");
+ }
builder.append("]");
return builder.toString();
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index d90f46d..3e353d6 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -354,6 +354,14 @@
public void onConnectionAdded(Connection connection) {}
/**
+ * Invoked when the conference adds a participant to the conference call.
+ *
+ * @param participant The participant to be added with conference call.
+ * @hide
+ */
+ public void onAddParticipant(String participant) {}
+
+ /**
* Sets state to be on hold.
*/
public final void setOnHold() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa16b84..2ee023e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -343,11 +343,25 @@
*/
public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
+ /**
+ * Add participant in an active or conference call option
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
+
/** Call supports the deflect feature. */
public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000;
+ /**
+ * Remote device supports RTT.
+ * @hide
+ */
+
+ public static final int CAPABILITY_SUPPORTS_RTT_REMOTE = 0x08000000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x04000000
+ // Next CAPABILITY value: 0x10000000
//**********************************************************************************************
/**
@@ -779,7 +793,9 @@
if ((capabilities & CAPABILITY_SUPPORT_DEFLECT) == CAPABILITY_SUPPORT_DEFLECT) {
builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def");
}
-
+ if ((capabilities & CAPABILITY_SUPPORTS_RTT_REMOTE) == CAPABILITY_SUPPORTS_RTT_REMOTE) {
+ builder.append(isLong ? " CAPABILITY_SUPPORTS_RTT_REMOTE" : " sup_rtt");
+ }
builder.append("]");
return builder.toString();
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0abd9fc..f988a13 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -184,6 +184,8 @@
private static final int MSG_HANDOVER_FAILED = 32;
private static final int MSG_HANDOVER_COMPLETE = 33;
private static final int MSG_DEFLECT = 34;
+ //Proprietary values starts after this.
+ private static final int MSG_ADD_PARTICIPANT_WITH_CONFERENCE = 40;
private static Connection sNullConnection;
@@ -518,6 +520,14 @@
}
@Override
+ public void addParticipantWithConference(String callId, String participant) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = participant;
+ mHandler.obtainMessage(MSG_ADD_PARTICIPANT_WITH_CONFERENCE, args).sendToTarget();
+ }
+
+ @Override
public void mergeConference(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_MERGE_CONFERENCE);
try {
@@ -980,6 +990,17 @@
}
break;
}
+ case MSG_ADD_PARTICIPANT_WITH_CONFERENCE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String participant = (String) args.arg2;
+ addParticipantWithConference(callId, participant);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_CONFERENCE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
@@ -1817,6 +1838,17 @@
}
}
+ private void addParticipantWithConference(String callId, String participant) {
+ Log.d(this, "ConnectionService addParticipantWithConference(%s, %s)", participant, callId);
+ Conference conference = findConferenceForAction(callId, "addParticipantWithConference");
+ Connection connection = findConnectionForAction(callId, "addParticipantWithConnection");
+ if (connection != getNullConnection()) {
+ onAddParticipant(connection, participant);
+ } else if (conference != getNullConference()) {
+ conference.onAddParticipant(participant);
+ }
+ }
+
private void mergeConference(String callId) {
Log.d(this, "mergeConference(%s)", callId);
Conference conference = findConferenceForAction(callId, "mergeConference");
@@ -2436,6 +2468,18 @@
*/
public void onConferenceRemoved(Conference conference) {}
+ /** Add participant with connection. Invoked when user has made a request to add
+ * participant with specified connection. In response, the participant should add with
+ * the connection.
+ *
+ * @param connection A connection where participant need to add.
+ * @param participant Address of participant which will be added.
+ * @return
+ *
+ * @hide
+ */
+ public void onAddParticipant(Connection connection, String participant) {}
+
/**
* Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
* When this method is invoked, this {@link ConnectionService} should create its own
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 625cd72..dc535be 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -183,6 +183,17 @@
"android.telecom.action.DEFAULT_DIALER_CHANGED";
/**
+ *@hide Broadcast intent action indicating the call type(CS call or Non-CS call).
+ * The string extra {@link #EXTRA_CALL_TYPE_CS} will contain the
+ * boolean value true if call is CS call else false.
+ *
+ * @see #EXTRA_CALL_TYPE_CS
+ */
+ public static final String ACTION_CALL_TYPE =
+ "codeaurora.telecom.action.CALL_TYPE";
+
+
+ /**
* Extra value used to provide the package name for {@link #ACTION_CHANGE_DEFAULT_DIALER}.
*/
public static final String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME =
@@ -380,6 +391,13 @@
"android.telecom.extra.CALL_NETWORK_TYPE";
/**
+ *@hide Extra value used to provide the call type for {@link #ACTION_CALL_TYPE}.
+ */
+ public static final String EXTRA_CALL_TYPE_CS =
+ "codeaurora.telecom.extra.CALL_TYPE_CS";
+
+
+ /**
* An optional {@link android.content.Intent#ACTION_CALL} intent extra denoting the
* package name of the app specifying an alternative gateway for the call.
* The value is a string.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index e35093c..acb3e6f 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -104,6 +104,8 @@
void respondToRttUpgradeRequest(String callId, in ParcelFileDescriptor fromInCall,
in ParcelFileDescriptor toInCall, in Session.Info sessionInfo);
+ void addParticipantWithConference(String callId, String recipients);
+
void connectionServiceFocusLost(in Session.Info sessionInfo);
void connectionServiceFocusGained(in Session.Info sessionInfo);
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index bc29b59..24cecb4 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -278,6 +278,13 @@
* <p>Type: TEXT</p>
*/
public static final String CREATOR = "creator";
+
+ /**
+ * The priority of the message.
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String PRIORITY = "priority";
}
/**
@@ -374,6 +381,7 @@
* @hide
*/
public static Cursor query(ContentResolver cr, String[] projection) {
+ android.util.SeempLog.record(10);
return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
}
@@ -384,6 +392,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static Cursor query(ContentResolver cr, String[] projection,
String where, String orderBy) {
+ android.util.SeempLog.record(10);
return cr.query(CONTENT_URI, projection, where,
null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
@@ -487,6 +496,31 @@
public static Uri addMessageToUri(int subId, ContentResolver resolver,
Uri uri, String address, String body, String subject,
Long date, boolean read, boolean deliveryReport, long threadId) {
+ return addMessageToUri(subId, resolver, uri, address, body, subject,
+ date, read, deliveryReport, threadId, -1);
+ }
+
+ /**
+ * Add an SMS to the given URI with thread_id specified.
+ *
+ * @param resolver the content resolver to use
+ * @param uri the URI to add the message to
+ * @param address the address of the sender
+ * @param body the body of the message
+ * @param subject the psuedo-subject of the message
+ * @param date the timestamp for the message
+ * @param read true if the message has been read, false if not
+ * @param deliveryReport true if a delivery report was requested, false if not
+ * @param threadId the thread_id of the message
+ * @param subId the subscription which the message belongs to
+ * @param priority the priority of the message
+ * @return the URI for the new message
+ * @hide
+ */
+ public static Uri addMessageToUri(int subId, ContentResolver resolver,
+ Uri uri, String address, String body, String subject,
+ Long date, boolean read, boolean deliveryReport,
+ long threadId, int priority) {
ContentValues values = new ContentValues(8);
Rlog.v(TAG,"Telephony addMessageToUri sub id: " + subId);
@@ -498,6 +532,7 @@
values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
values.put(SUBJECT, subject);
values.put(BODY, body);
+ values.put(PRIORITY, priority);
if (deliveryReport) {
values.put(STATUS, STATUS_PENDING);
}
@@ -2032,6 +2067,20 @@
* <P>Type: INTEGER (boolean)</P>
*/
public static final String ARCHIVED = "archived";
+
+ /**
+ * Indicates the last mms type in the thread.
+ * <P>Type: TEXT</P>
+ * @hide
+ */
+ public static final String ATTACHMENT_INFO = "attachment_info";
+
+ /**
+ * Indicates whether this thread is a notification thread.
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String NOTIFICATION = "notification";
}
/**
@@ -2832,6 +2881,7 @@
*/
public static Cursor query(
ContentResolver cr, String[] projection) {
+ android.util.SeempLog.record(10);
return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
}
@@ -2842,6 +2892,7 @@
public static Cursor query(
ContentResolver cr, String[] projection,
String where, String orderBy) {
+ android.util.SeempLog.record(10);
return cr.query(CONTENT_URI, projection,
where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
}
diff --git a/telephony/java/android/telephony/CallerInfo.java b/telephony/java/android/telephony/CallerInfo.java
index f87ac50..6fb9bf2 100644
--- a/telephony/java/android/telephony/CallerInfo.java
+++ b/telephony/java/android/telephony/CallerInfo.java
@@ -205,6 +205,7 @@
* @hide
*/
public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
+ android.util.SeempLog.record_uri(12, contactRef);
CallerInfo info = new CallerInfo();
info.photoResource = 0;
info.phoneLabel = null;
@@ -397,6 +398,7 @@
*/
@UnsupportedAppUsage
public static CallerInfo getCallerInfo(Context context, String number, int subId) {
+ android.util.SeempLog.record_str(12, "number="+number+",subId="+subId);
if (TextUtils.isEmpty(number)) {
return null;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 047b220..e2f60b8 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -569,6 +569,14 @@
public static final String KEY_VILTE_DATA_IS_METERED_BOOL = "vilte_data_is_metered_bool";
/**
+ * Flag indicating whether we should reset UT capability or not for IMS deregistration
+ * and for IMS feature state not ready
+ * @hide
+ */
+ public static final String KEY_IGNORE_RESET_UT_CAPABILITY_BOOL =
+ "ignore_reset_ut_capability_bool";
+
+ /**
* Flag specifying whether WFC over IMS should be available for carrier: independent of
* carrier provisioning. If false: hard disabled. If true: then depends on carrier
* provisioning, availability etc.
@@ -1501,6 +1509,12 @@
"show_precise_failed_cause_bool";
/**
+ * Flag specifying whether CDMA call waiting and call forwarding are enabled
+ * @hide
+ */
+ public static final String KEY_CDMA_CW_CF_ENABLED_BOOL = "cdma_cw_cf_enabled_bool";
+
+ /**
* Boolean to decide whether lte is enabled.
* @hide
*/
@@ -1532,8 +1546,8 @@
public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
"carrier_settings_activity_component_name_string";
- // These variables are used by the MMS service and exposed through another API,
- // SmsManager. The variable names and string values are copied from there.
+ // These variables are used by the MMS service and exposed through another API, {@link
+ // SmsManager}. The variable names and string values are copied from there.
public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio";
public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID";
@@ -1924,6 +1938,13 @@
"allow_add_call_during_video_call";
/**
+ * When false, indicates that holding a video call is disabled
+ * @hide
+ */
+ public static final String KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL =
+ "allow_holding_video_call";
+
+ /**
* When true, indicates that the HD audio icon in the in-call screen should not be shown for
* VoWifi calls.
* @hide
@@ -2389,6 +2410,12 @@
public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
/**
+ * Flag indicating whether RTT is always enabled.
+ * @hide
+ */
+ public static final String KEY_RTT_ALWAYS_ENABLED_BOOL = "rtt_always_enabled_bool";
+
+ /**
* Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu
* if the device is capable of RTT.
* @hide
@@ -3245,6 +3272,7 @@
sDefaults.putBoolean(KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true);
sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
+ sDefaults.putBoolean(KEY_IGNORE_RESET_UT_CAPABILITY_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
@@ -3281,7 +3309,7 @@
sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
- sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
+ sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, true);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
@@ -3353,6 +3381,7 @@
new String[]{"default", "mms", "dun", "supl"});
sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
+ sDefaults.putBoolean(KEY_CDMA_CW_CF_ENABLED_BOOL, false);
sDefaults.putStringArray(KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
new String[]{""});
sDefaults.putStringArray(KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
@@ -3510,6 +3539,7 @@
sDefaults.putBoolean(KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL, true);
sDefaults.putBoolean(KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL, true);
+ sDefaults.putBoolean(KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
sDefaults.putBoolean(KEY_WIFI_CALLS_CAN_BE_HD_AUDIO, true);
sDefaults.putBoolean(KEY_VIDEO_CALLS_CAN_BE_HD_AUDIO, true);
sDefaults.putBoolean(KEY_GSM_CDMA_CALLS_CAN_BE_HD_AUDIO, false);
@@ -3549,6 +3579,7 @@
sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
+ sDefaults.putBoolean(KEY_RTT_ALWAYS_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 1912c60..c8146dc 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -194,13 +194,13 @@
/** @hide */
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
- if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+ if (mSsRsrp == CellInfo.UNAVAILABLE) {
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+ } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
mLevel = SIGNAL_STRENGTH_GREAT;
- } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+ } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
mLevel = SIGNAL_STRENGTH_GOOD;
- } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+ } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
mLevel = SIGNAL_STRENGTH_MODERATE;
} else {
mLevel = SIGNAL_STRENGTH_POOR;
@@ -231,11 +231,11 @@
}
/**
- * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+ * Get the SS-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
*/
@Override
public int getDbm() {
- return mCsiRsrp;
+ return mSsRsrp;
}
/** @hide */
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index aa7e21a..160534d 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -353,12 +353,124 @@
*/
public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+ /** @hide */
+ public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 80;
+ /** @hide */
+ public static final int BEARER_CAPABILITY_UNAVAILABLE = 81;
+ /** @hide */
+ public static final int SERVICE_OPTION_NOT_AVAILABLE = 82;
+ /** @hide */
+ public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 83;
+ /** @hide */
+ public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 84;
+ /** @hide */
+ public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 85;
+ /** @hide */
+ public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 86;
+ /** @hide */
+ public static final int INVALID_TRANSACTION_IDENTIFIER = 87;
+ /** @hide */
+ public static final int USER_NOT_MEMBER_OF_CUG = 88;
+ /** @hide */
+ public static final int INCOMPATIBLE_DESTINATION = 89;
+ /** @hide */
+ public static final int INVALID_TRANSIT_NW_SELECTION = 90;
+ /** @hide */
+ public static final int SEMANTICALLY_INCORRECT_MESSAGE = 91;
+ /** @hide */
+ public static final int INVALID_MANDATORY_INFORMATION = 92;
+ /** @hide */
+ public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 93;
+ /** @hide */
+ public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 94;
+ /** @hide */
+ public static final int INFORMATION_ELEMENT_NON_EXISTENT = 95;
+ /** @hide */
+ public static final int CONDITIONAL_IE_ERROR = 96;
+ /** @hide */
+ public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 97;
+ /** @hide */
+ public static final int RECOVERY_ON_TIMER_EXPIRED = 98;
+ /** @hide */
+ public static final int PROTOCOL_ERROR_UNSPECIFIED = 99;
+ /** @hide */
+ public static final int INTERWORKING_UNSPECIFIED = 100;
+ /** @hide */
+ public static final int LOCAL_LOW_BATTERY = 101;
+ /** @hide */
+ public static final int NO_CIRCUIT_AVAIL = 102;
+ /** @hide */
+ public static final int NO_ROUTE_TO_DESTINATION = 103;
+ /** @hide */
+ public static final int OPERATOR_DETERMINED_BARRING = 104;
+ /** @hide */
+ public static final int CALL_FAIL_NO_USER_RESPONDING = 105;
+ /** @hide */
+ public static final int CALL_FAIL_NO_ANSWER_FROM_USER = 106;
+ /** @hide */
+ public static final int CALL_FAIL_DESTINATION_OUT_OF_ORDER = 107;
+ /** @hide */
+ public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 108;
+ /** @hide */
+ public static final int CHANNEL_UNACCEPTABLE = 109;
+ /** @hide */
+ public static final int CALL_REJECTED = 110;
+ /** @hide */
+ public static final int NUMBER_CHANGED = 111;
+ /** @hide */
+ public static final int PREEMPTION = 112;
+ /** @hide */
+ public static final int FACILITY_REJECTED = 113;
+ /** @hide */
+ public static final int RESP_TO_STATUS_ENQUIRY = 114;
+ /** @hide */
+ public static final int NETWORK_OUT_OF_ORDER = 115;
+ /** @hide */
+ public static final int TEMPORARY_FAILURE = 116;
+ /** @hide */
+ public static final int SWITCHING_EQUIPMENT_CONGESTION = 117;
+ /** @hide */
+ public static final int ACCESS_INFORMATION_DISCARDED = 118;
+ /** @hide */
+ public static final int REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 119;
+ /** @hide */
+ public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 120;
+ /** @hide */
+ public static final int QOS_UNAVAILABLE = 121;
+ /** @hide */
+ public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 122;
+
+ /**
+ * call failed due to LTE to 3G/2G handover not feasible
+ * @hide
+ */
+ public static final int HO_NOT_FEASIBLE = 123;
+ /** @hide */
+ public static final int NON_SELECTED_USER_CLEARING = 124;
+
//*********************************************************************************************
// When adding a disconnect type:
- // 1) Update toString() with the newly added disconnect type.
- // 2) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
+ // 1) Please assign the new type the next id value below.
+ // 2) Increment the next id value below to a new value.
+ // 3) Update MAXIMUM_VALID_VALUE to the new disconnect type.
+ // 4) Update toString() with the newly added disconnect type.
+ // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
+ //
+ // NextId: 123
//*********************************************************************************************
+ /**
+ * Smallest valid value for call disconnect codes.
+ * @hide
+ */
+ public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
+
+ /**
+ * Largest valid value for call disconnect codes.
+ * @hide
+ */
+ public static final int MAXIMUM_VALID_VALUE = NON_SELECTED_USER_CLEARING;
+
/** Private constructor to avoid class instantiation. */
private DisconnectCause() {
// Do nothing.
@@ -507,6 +619,32 @@
return "EMERGENCY_TEMP_FAILURE";
case EMERGENCY_PERM_FAILURE:
return "EMERGENCY_PERM_FAILURE";
+ case NO_CIRCUIT_AVAIL:
+ return "NO_CIRCUIT_AVAIL";
+ case NO_ROUTE_TO_DESTINATION:
+ return "NO_ROUTE_TO_DESTINATION";
+ case OPERATOR_DETERMINED_BARRING:
+ return "OPERATOR_DETERMINED_BARRING";
+ case CALL_FAIL_NO_USER_RESPONDING:
+ return "CALL_FAIL_NO_USER_RESPONDING";
+ case CALL_FAIL_NO_ANSWER_FROM_USER:
+ return "CALL_FAIL_NO_ANSWER_FROM_USER";
+ case CALL_FAIL_DESTINATION_OUT_OF_ORDER:
+ return "CALL_FAIL_DESTINATION_OUT_OF_ORDER";
+ case BEARER_CAPABILITY_NOT_AUTHORIZED:
+ return "BEARER_CAPABILITY_NOT_AUTHORIZED";
+ case CHANNEL_UNACCEPTABLE:
+ return "CHANNEL_UNACCEPTABLE";
+ case CALL_REJECTED:
+ return "CALL_REJECTED";
+ case NUMBER_CHANGED:
+ return "NUMBER_CHANGED";
+ case PREEMPTION:
+ return "PREEMPTION";
+ case FACILITY_REJECTED:
+ return "FACILITY_REJECTED";
+ case RESP_TO_STATUS_ENQUIRY:
+ return "RESP_TO_STATUS_ENQUIRY";
case NORMAL_UNSPECIFIED:
return "NORMAL_UNSPECIFIED";
case IMS_SIP_ALTERNATE_EMERGENCY_CALL:
@@ -527,6 +665,70 @@
return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
+ case NETWORK_OUT_OF_ORDER:
+ return "NETWORK_OUT_OF_ORDER";
+ case TEMPORARY_FAILURE:
+ return "TEMPORARY_FAILURE";
+ case SWITCHING_EQUIPMENT_CONGESTION:
+ return "SWITCHING_EQUIPMENT_CONGESTION";
+ case ACCESS_INFORMATION_DISCARDED:
+ return "ACCESS_INFORMATION_DISCARDED";
+ case REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE:
+ return "REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE";
+ case RESOURCES_UNAVAILABLE_OR_UNSPECIFIED:
+ return "RESOURCES_UNAVAILABLE_OR_UNSPECIFIED";
+ case QOS_UNAVAILABLE:
+ return "QOS_UNAVAILABLE";
+ case REQUESTED_FACILITY_NOT_SUBSCRIBED:
+ return "REQUESTED_FACILITY_NOT_SUBSCRIBED";
+ case INCOMING_CALLS_BARRED_WITHIN_CUG:
+ return "INCOMING_CALLS_BARRED_WITHIN_CUG";
+ case BEARER_CAPABILITY_UNAVAILABLE:
+ return "BEARER_CAPABILITY_UNAVAILABLE";
+ case SERVICE_OPTION_NOT_AVAILABLE:
+ return "SERVICE_OPTION_NOT_AVAILABLE";
+ case BEARER_SERVICE_NOT_IMPLEMENTED:
+ return "BEARER_SERVICE_NOT_IMPLEMENTED";
+ case REQUESTED_FACILITY_NOT_IMPLEMENTED:
+ return "REQUESTED_FACILITY_NOT_IMPLEMENTED";
+ case ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE:
+ return "ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE";
+ case SERVICE_OR_OPTION_NOT_IMPLEMENTED:
+ return "SERVICE_OR_OPTION_NOT_IMPLEMENTED";
+ case INVALID_TRANSACTION_IDENTIFIER:
+ return "INVALID_TRANSACTION_IDENTIFIER";
+ case USER_NOT_MEMBER_OF_CUG:
+ return "USER_NOT_MEMBER_OF_CUG";
+ case INCOMPATIBLE_DESTINATION:
+ return "INCOMPATIBLE_DESTINATION";
+ case INVALID_TRANSIT_NW_SELECTION:
+ return "INVALID_TRANSIT_NW_SELECTION";
+ case SEMANTICALLY_INCORRECT_MESSAGE:
+ return "SEMANTICALLY_INCORRECT_MESSAGE";
+ case INVALID_MANDATORY_INFORMATION:
+ return "INVALID_MANDATORY_INFORMATION";
+ case MESSAGE_TYPE_NON_IMPLEMENTED:
+ return "MESSAGE_TYPE_NON_IMPLEMENTED";
+ case MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE:
+ return "MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE";
+ case INFORMATION_ELEMENT_NON_EXISTENT:
+ return "INFORMATION_ELEMENT_NON_EXISTENT";
+ case CONDITIONAL_IE_ERROR:
+ return "CONDITIONAL_IE_ERROR";
+ case MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE:
+ return "MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE";
+ case RECOVERY_ON_TIMER_EXPIRED:
+ return "RECOVERY_ON_TIMER_EXPIRED";
+ case PROTOCOL_ERROR_UNSPECIFIED:
+ return "PROTOCOL_ERROR_UNSPECIFIED";
+ case INTERWORKING_UNSPECIFIED:
+ return "INTERWORKING_UNSPECIFIED";
+ case LOCAL_LOW_BATTERY:
+ return "LOCAL_LOW_BATTERY";
+ case HO_NOT_FEASIBLE:
+ return "HO_NOT_FEASIBLE";
+ case NON_SELECTED_USER_CLEARING:
+ return "NON_SELECTED_USER_CLEARING";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index af3ba5e..2efc802 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -28,6 +28,7 @@
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
+import android.location.Country;
import android.location.CountryDetector;
import android.net.Uri;
import android.os.PersistableBundle;
@@ -110,6 +111,7 @@
private static final String BCD_EF_ADN_EXTENDED = "*#,N;";
private static final String BCD_CALLED_PARTY_EXTENDED = "*#abc";
+ private static Country sCountryDetector = null;
/*
* global-phone-number = ["+"] 1*( DIGIT / written-sep )
* written-sep = ("-"/".")
@@ -2190,12 +2192,9 @@
private static boolean isLocalEmergencyNumberInternal(int subId, String number,
Context context,
boolean useExactMatch) {
- String countryIso;
- CountryDetector detector = (CountryDetector) context.getSystemService(
- Context.COUNTRY_DETECTOR);
- if (detector != null && detector.detectCountry() != null) {
- countryIso = detector.detectCountry().getCountryIso();
- } else {
+ String countryIso = getCountryIso(context);
+ Rlog.w(LOG_TAG, "isLocalEmergencyNumberInternal" + countryIso);
+ if (countryIso == null) {
Locale locale = context.getResources().getConfiguration().locale;
countryIso = locale.getCountry();
Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
@@ -2204,6 +2203,28 @@
return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
}
+ private static String getCountryIso(Context context) {
+ Rlog.w(LOG_TAG, "getCountryIso " + sCountryDetector);
+ if (sCountryDetector == null) {
+ CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ sCountryDetector = detector.detectCountry();
+ }
+ }
+
+ if (sCountryDetector == null) {
+ return null;
+ } else {
+ return sCountryDetector.getCountryIso();
+ }
+ }
+
+ /** @hide */
+ public static void resetCountryDetectorInfo() {
+ sCountryDetector = null;
+ }
+
/**
* isVoiceMailNumber: checks a given number against the voicemail
* number provided by the RIL and SIM card. The caller must have
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f503348..91c917c 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1697,6 +1697,13 @@
}
/** @hide */
+ public static boolean isPsTech(int radioTechnology) {
+ return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE ||
+ radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA ||
+ radioTechnology == RIL_RADIO_TECHNOLOGY_NR;
+ }
+
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static boolean bearerBitmapHasCdma(int networkTypeBitmask) {
return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 2d35f8e..ae6831b 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -351,6 +351,7 @@
public void sendTextMessage(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
+ android.util.SeempLog.record_str(75, destinationAddress);
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
true /* persistMessage*/, ActivityThread.currentPackageName());
}
@@ -1076,6 +1077,7 @@
public void sendDataMessage(
String destinationAddress, String scAddress, short destinationPort,
byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
+ android.util.SeempLog.record_str(73, destinationAddress);
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}
@@ -1398,6 +1400,7 @@
*/
@UnsupportedAppUsage
public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
+ android.util.SeempLog.record(79);
boolean success = false;
if (null == pdu) {
@@ -1440,6 +1443,7 @@
@UnsupportedAppUsage
public boolean
deleteMessageFromIcc(int messageIndex) {
+ android.util.SeempLog.record(80);
boolean success = false;
try {
@@ -1482,6 +1486,7 @@
*/
@UnsupportedAppUsage
public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
+ android.util.SeempLog.record(81);
boolean success = false;
try {
@@ -1795,6 +1800,25 @@
}
}
+ /**
+ * Get the capacity count of sms on Icc card
+ *
+ * @return the capacity count of sms on Icc card
+ * @hide
+ */
+ public int getSmsCapacityOnIcc() {
+ int ret = -1;
+ try {
+ ISms iccISms = getISmsService();
+ if (iccISms != null) {
+ ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId());
+ }
+ } catch (RemoteException ex) {
+ //ignore it
+ }
+ return ret;
+ }
+
// see SmsMessage.getStatusOnIcc
/** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f83520f..7549adc 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1728,6 +1728,7 @@
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
+ android.util.SeempLog.record_str(8, ""+slotIndex);
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
@@ -2005,6 +2006,7 @@
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public CellLocation getCellLocation() {
+ android.util.SeempLog.record(49);
try {
ITelephony telephony = getITelephony();
if (telephony == null) {
@@ -2096,6 +2098,7 @@
@Deprecated
@RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
public List<NeighboringCellInfo> getNeighboringCellInfo() {
+ android.util.SeempLog.record(50);
try {
ITelephony telephony = getITelephony();
if (telephony == null)
@@ -3593,6 +3596,7 @@
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public String getSimSerialNumber(int subId) {
+ android.util.SeempLog.record_str(388, ""+subId);
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
@@ -3865,6 +3869,7 @@
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSubscriberId(int subId) {
+ android.util.SeempLog.record_str(389, ""+subId);
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
@@ -4096,6 +4101,7 @@
})
@UnsupportedAppUsage
public String getLine1Number(int subId) {
+ android.util.SeempLog.record_str(9, ""+subId);
String number = null;
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 2161dcb..ae73933 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1191,16 +1191,16 @@
&& !other.canHandleType(TYPE_DUN)
&& Objects.equals(this.mApnName, other.mApnName)
&& !typeSameAny(this, other)
- && xorEquals(this.mProxyAddress, other.mProxyAddress)
+ && xorEqualsString(this.mProxyAddress, other.mProxyAddress)
&& xorEqualsInt(this.mProxyPort, other.mProxyPort)
- && xorEquals(this.mProtocol, other.mProtocol)
- && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
+ && xorEqualsInt(this.mProtocol, other.mProtocol)
+ && xorEqualsInt(this.mRoamingProtocol, other.mRoamingProtocol)
&& Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(this.mProfileId, other.mProfileId)
&& Objects.equals(this.mMvnoType, other.mMvnoType)
&& Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
&& xorEquals(this.mMmsc, other.mMmsc)
- && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+ && xorEqualsString(this.mMmsProxyAddress, other.mMmsProxyAddress)
&& xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
&& Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
&& Objects.equals(mApnSetId, other.mApnSetId)
@@ -1213,6 +1213,11 @@
return first == null || second == null || first.equals(second);
}
+ // Equal or one is null or "".
+ private boolean xorEqualsString(String first, String second) {
+ return TextUtils.isEmpty(first) || TextUtils.isEmpty(second) || first.equals(second);
+ }
+
// Equal or one is not specified.
private boolean xorEqualsInt(int first, int second) {
return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 4ddeb90..fd3a3d5 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -110,6 +110,11 @@
* VideoShare (video RX one way)
*/
public static final int CALL_TYPE_VS_RX = 10;
+ /**
+ * Unknown (audio / video inactive)
+ * @hide
+ */
+ public static final int CALL_TYPE_UNKNOWN = (-1);
/**
* Extra properties for IMS call.
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index fcd7faf..85ab409 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -52,6 +52,12 @@
}
@Override
+ public int queryCFForServiceClass(int condition, String number, int serviceClass) throws
+ RemoteException {
+ return ImsUtImplBase.this.queryCFForServiceClass(condition, number, serviceClass);
+ }
+
+ @Override
public int queryCallWaiting() throws RemoteException {
return ImsUtImplBase.this.queryCallWaiting();
}
@@ -169,6 +175,14 @@
}
/**
+ * Retrieves the configuration of the call forward for specified service class.
+ */
+ public int queryCFForServiceClass(int condition, String number,
+ int serviceClass) {
+ return -1;
+ }
+
+ /**
* Retrieves the configuration of the call waiting.
*/
public int queryCallWaiting() {
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index c9d4405..3abc7c6 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -124,6 +124,12 @@
public void queryCallForward(int condition, String number, Message result);
/**
+ * Retrieves the configuration of the call forward for the specified service class.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
+ */
+ public void queryCallForward(int condition, String number,
+ int serviceClass, Message result);
+ /**
* Retrieves the configuration of the call waiting.
* The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
*/
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4f97cc5..ca10b2d 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -122,4 +122,12 @@
*/
int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
int serviceClass);
+
+ /**
+ * Retrieves the configuration of the call forward for specified service class.
+ * Returns an integer value to indicate the requestId of the UT request.
+ * -1 is returned if the "condition" is invalid for the queryCallForward,
+ * otherwise, integer greater than -1 will be returned.
+ */
+ int queryCFForServiceClass(int condition, String number, int serviceClass);
}
diff --git a/telephony/java/com/android/ims/internal/uce/common/CapInfo.java b/telephony/java/com/android/ims/internal/uce/common/CapInfo.java
index a9847ba..24e2260 100644
--- a/telephony/java/com/android/ims/internal/uce/common/CapInfo.java
+++ b/telephony/java/com/android/ims/internal/uce/common/CapInfo.java
@@ -65,6 +65,20 @@
private boolean mRcsIpVideoCallSupported = false;
/** RCS IP Video call support . */
private boolean mRcsIpVideoOnlyCallSupported = false;
+ /** IP Geo location Push using SMS. */
+ private boolean mGeoSmsSupported = false;
+ /** RCS call composer support. */
+ private boolean mCallComposerSupported = false;
+ /** RCS post-call support. */
+ private boolean mPostCallSupported = false;
+ /** Shared map support. */
+ private boolean mSharedMapSupported = false;
+ /** Shared Sketch supported. */
+ private boolean mSharedSketchSupported = false;
+ /** Chatbot communication support. */
+ private boolean mChatbotSupported = false;
+ /** Chatbot role support. */
+ private boolean mChatbotRoleSupported = false;
/** List of supported extensions. */
private String[] mExts = new String[10];
/** Time used to compute when to query again. */
@@ -387,6 +401,118 @@
this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported;
}
+ /**
+ * Checks whether Geo Push via SMS is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isGeoSmsSupported() {
+ return mGeoSmsSupported;
+ }
+
+ /**
+ * Sets Geolocation Push via SMS as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setGeoSmsSupported(boolean geoSmsSupported) {
+ this.mGeoSmsSupported = geoSmsSupported;
+ }
+
+ /**
+ * Checks whether RCS call composer is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isCallComposerSupported() {
+ return mCallComposerSupported;
+ }
+
+ /**
+ * Sets call composer as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setCallComposerSupported(boolean callComposerSupported) {
+ this.mCallComposerSupported = callComposerSupported;
+ }
+
+ /**
+ * Checks whether post call is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isPostCallSupported(){
+ return mPostCallSupported;
+ }
+
+ /**
+ * Sets post call as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setPostCallSupported(boolean postCallSupported) {
+ this.mPostCallSupported = postCallSupported;
+ }
+
+ /**
+ * Checks whether shared map is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isSharedMapSupported() {
+ return mSharedMapSupported;
+ }
+
+ /**
+ * Sets shared map as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setSharedMapSupported(boolean sharedMapSupported) {
+ this.mSharedMapSupported = sharedMapSupported;
+ }
+
+ /**
+ * Checks whether shared sketch is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isSharedSketchSupported() {
+ return mSharedSketchSupported;
+ }
+
+ /**
+ * Sets shared sketch as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setSharedSketchSupported(boolean sharedSketchSupported) {
+ this.mSharedSketchSupported = sharedSketchSupported;
+ }
+
+ /**
+ * Checks whether chatbot communication is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isChatbotSupported() {
+ return mChatbotSupported;
+ }
+
+ /**
+ * Sets chatbot communication as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setChatbotSupported(boolean chatbotSupported) {
+ this.mChatbotSupported = chatbotSupported;
+ }
+
+ /**
+ * Checks whether chatbot role is supported.
+ */
+ @UnsupportedAppUsage
+ public boolean isChatbotRoleSupported() {
+ return mChatbotRoleSupported;
+ }
+
+ /**
+ * Sets chatbot role as supported or not supported.
+ */
+ @UnsupportedAppUsage
+ public void setChatbotRoleSupported(boolean chatbotRoleSupported) {
+ this.mChatbotRoleSupported = chatbotRoleSupported;
+ }
+
/** Gets the list of supported extensions. */
public String[] getExts() {
return mExts;
@@ -435,6 +561,13 @@
dest.writeInt(mGeoPushSupported ? 1 : 0);
dest.writeInt(mSmSupported ? 1 : 0);
dest.writeInt(mFullSnFGroupChatSupported ? 1 : 0);
+ dest.writeInt(mGeoSmsSupported ? 1 : 0);
+ dest.writeInt(mCallComposerSupported ? 1 : 0);
+ dest.writeInt(mPostCallSupported ? 1 : 0);
+ dest.writeInt(mSharedMapSupported ? 1 : 0);
+ dest.writeInt(mSharedSketchSupported ? 1 : 0);
+ dest.writeInt(mChatbotSupported ? 1 : 0);
+ dest.writeInt(mChatbotRoleSupported ? 1 : 0);
dest.writeInt(mRcsIpVoiceCallSupported ? 1 : 0);
dest.writeInt(mRcsIpVideoCallSupported ? 1 : 0);
@@ -477,6 +610,13 @@
mGeoPushSupported = (source.readInt() == 0) ? false : true;
mSmSupported = (source.readInt() == 0) ? false : true;
mFullSnFGroupChatSupported = (source.readInt() == 0) ? false : true;
+ mGeoSmsSupported = (source.readInt() == 0) ? false : true;
+ mCallComposerSupported = (source.readInt() == 0) ? false : true;
+ mPostCallSupported = (source.readInt() == 0) ? false : true;
+ mSharedMapSupported = (source.readInt() == 0) ? false : true;
+ mSharedSketchSupported = (source.readInt() == 0) ? false : true;
+ mChatbotSupported = (source.readInt() == 0) ? false : true;
+ mChatbotRoleSupported = (source.readInt() == 0) ? false : true;
mRcsIpVoiceCallSupported = (source.readInt() == 0) ? false : true;
mRcsIpVideoCallSupported = (source.readInt() == 0) ? false : true;
diff --git a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
index 87193e3..4614a80 100644
--- a/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
+++ b/telephony/java/com/android/ims/internal/uce/presence/PresPublishTriggerType.java
@@ -47,6 +47,10 @@
public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_IWLAN = 8;
/** Trigger is unknown. */
public static final int UCE_PRES_PUBLISH_TRIGGER_UNKNOWN = 9;
+ /** Move to 5G NR with VoPS disabled. */
+ public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10;
+ /** Move to 5G NR with VoPS enabled. */
+ public static final int UCE_PRES_PUBLISH_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11;
@@ -113,4 +117,4 @@
public void readFromParcel(Parcel source) {
mPublishTriggerType = source.readInt();
}
-}
\ No newline at end of file
+}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index f3a335d..6289c0e 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -569,6 +569,14 @@
int subId, String callingPkg, String prefixes, in PendingIntent intent);
/**
+ * Get the capacity count of sms on Icc card.
+ *
+ * @param subId for subId which getSmsCapacityOnIcc is queried.
+ * @return capacity of ICC
+ */
+ int getSmsCapacityOnIccForSubscriber(int subId);
+
+ /**
* Check if the destination is a possible premium short code.
*
* @param destAddress the destination address to test for possible short code
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 2096325..b7ec9fc 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -197,6 +197,11 @@
}
@Override
+ public int getSmsCapacityOnIccForSubscriber(int subId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public int checkSmsShortCodeDestination(
int subid, String callingApk, String destAddress, String countryIso) {
throw new UnsupportedOperationException();
diff --git a/telephony/java/com/android/internal/telephony/ISmsSecurityAgent.aidl b/telephony/java/com/android/internal/telephony/ISmsSecurityAgent.aidl
new file mode 100644
index 0000000..3b52529
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISmsSecurityAgent.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.SmsAuthorizationRequest;
+
+/**
+ * ISmsSecurityAgent enhances the security of outgoing SMS messages by allowing trusted system
+ * components to inspect and authorize or reject outgoing SMS messages.
+ *
+ * @hide
+ **/
+interface ISmsSecurityAgent {
+ /**
+ * Called when a SMS message is queued for dispatch allowing a registered
+ * agent to decide on whether to accept/reject the request to send an SMS message.
+ * <b>Unless the agent rejects the request within the OEM specific timeout, the SMS
+ * will be sent.</b>
+ * @param request the object containing information regarding the message and
+ * through which the agent can accept/reject the request.
+ */
+ void onAuthorize(in SmsAuthorizationRequest request);
+
+}
diff --git a/telephony/java/com/android/internal/telephony/ISmsSecurityService.aidl b/telephony/java/com/android/internal/telephony/ISmsSecurityService.aidl
new file mode 100644
index 0000000..e479f0c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISmsSecurityService.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.ISmsSecurityAgent;
+import com.android.internal.telephony.SmsAuthorizationRequest;
+
+/**
+ * ISmsSecurityService exposes a service that monitors the dispatch of outgoing SMS messages
+ * and notifies a registered ISmsSecurityAgent in order to authorize or reject the dispatch
+ * of each outgoing SMS message.
+ *
+ * @hide
+ */
+interface ISmsSecurityService {
+ /**
+ * Registers an agent in order to receive requests for outgoing SMS messages on which
+ * it can accept or reject the request for the dispatch of each SMS message.
+ * <b>Only one agent can be registered at one time.</b>
+ * @param agent the agent to be registered.
+ * @return true if the registration succeeds, false otherwise.
+ */
+ boolean register(in ISmsSecurityAgent agent);
+
+ /**
+ * Unregisters the previously registered agent and causes the security
+ * service to no longer rely on the agent for a decision regarding
+ * successive SMS messages being dispatched allowing all successive messages to be dispatched.
+ *
+ * @param agent the agent to be unregistered.
+ * @return true if the unregistration succeeds, false otherwise.
+ */
+ boolean unregister(in ISmsSecurityAgent agent);
+
+ /**
+ * Allows the registered ISmsSecurityAgent implementation to asynchronously send a response
+ * on whether it will accept/reject the dispatch of the SMS message.
+ * <b>If the agent responds after the OEM defined timeout it may not be able to
+ * interfere on whether the SMS was sent or not.</b>
+ * @param request the request related to an outgoing SMS message to accept/reject.
+ * @param accepted true to accept, false to reject.
+ * return true if the response took effect, false if a response has already been sent for this
+ * request or an OEM specific timeout already happened.
+ */
+ boolean sendResponse(in SmsAuthorizationRequest request, boolean authorized);
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.aidl b/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.aidl
new file mode 100644
index 0000000..a2f7020
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.internal.telephony;
+
+/** @hide */
+parcelable SmsAuthorizationRequest;
diff --git a/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.java b/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.java
new file mode 100644
index 0000000..bc64fa8
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsAuthorizationRequest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+/**
+ * This class represents a request from the {@link ISmsSecurityService} to trusted parties
+ * in order to allow third party components to participate in the decision process to accept
+ * or reject a request to send an SMS message.
+ *
+ * @hide
+ */
+public class SmsAuthorizationRequest implements Parcelable {
+
+ private final ISmsSecurityService service;
+
+ private final IBinder token;
+
+ public final String packageName;
+
+ public final String destinationAddress;
+
+ public final String message;
+
+ public SmsAuthorizationRequest(final Parcel source) {
+ this.service = ISmsSecurityService.Stub.asInterface(source.readStrongBinder());
+ this.token = source.readStrongBinder();
+ this.packageName = source.readString();
+ this.destinationAddress = source.readString();
+ this.message = source.readString();
+ }
+
+ public SmsAuthorizationRequest(final ISmsSecurityService service,
+ final IBinder binderToken,
+ final String packageName,
+ final String destinationAddress,
+ final String message) {
+ this.service = service;
+ this.token = binderToken;
+ this.packageName = packageName;
+ this.destinationAddress = destinationAddress;
+ this.message = message;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ dest.writeStrongBinder(service.asBinder());
+ dest.writeStrongBinder(token);
+ dest.writeString(packageName);
+ dest.writeString(destinationAddress);
+ dest.writeString(message);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static Parcelable.Creator<SmsAuthorizationRequest> CREATOR =
+ new Creator<SmsAuthorizationRequest>() {
+ @Override
+ public SmsAuthorizationRequest[] newArray(final int size) {
+ return new SmsAuthorizationRequest[size];
+ }
+
+ @Override
+ public SmsAuthorizationRequest createFromParcel(final Parcel source) {
+ return new SmsAuthorizationRequest(source);
+ }
+ };
+
+ public void accept() throws RemoteException{
+ service.sendResponse(this, true);
+ }
+
+ public void reject() throws RemoteException {
+ service.sendResponse(this, false);
+ }
+
+ public IBinder getToken() {
+ return token;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s] (%s) # %s",
+ this.packageName,
+ this.destinationAddress,
+ this.message);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 4e42c20..2a744c9 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -241,4 +241,35 @@
* Type: int
*/
static final String PROPERTY_MAX_ACTIVE_MODEMS = "ro.telephony.max.active.modems";
+
+ /**
+ * Used when Presence app sends Dial intent with specific schema
+ * If true: skip schema parsing and use Tel schema
+ * If false: parse schema
+ */
+ static final String EXTRA_SKIP_SCHEMA_PARSING =
+ "org.codeaurora.extra.SKIP_SCHEMA_PARSING";
+
+ /**
+ * For Group Conference Calling
+ * If true: isConferenceUri in Dial is set to true,
+ * which indicates that Dial is for Conference Calling
+ * If false: above is set to false
+ */
+ static final String EXTRAS_IS_CONFERENCE_URI = "isConferenceUri";
+
+ /**
+ * For Group Conference Dialing Feature
+ * If true: Dial intent triggered from Group Conference Calling screen
+ * if false: normal dial
+ */
+ static final String EXTRA_DIAL_CONFERENCE_URI =
+ "org.codeaurora.extra.DIAL_CONFERENCE_URI";
+
+ /**
+ * For Add Participant Feature
+ * If true: Dial intent triggered from Dialpad is for AddParticipant
+ * if false: normal dial
+ */
+ static final String ADD_PARTICIPANT_KEY = "add_participant";
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
old mode 100644
new mode 100755
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index c924ab3..38154b8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -39,6 +39,7 @@
static public final int TELESERVICE_WAP = 0x1004;
static public final int TELESERVICE_WEMT = 0x1005;
static public final int TELESERVICE_SCPT = 0x1006;
+ static public final int TELESERVICE_CT_WAP = 0xFDEA;
/** Carriers specific Teleservice IDs. */
public static final int TELESERVICE_FDEA_WAP = 0xFDEA; // 65002
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index f2d4624..3dc2e90 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -23,11 +23,13 @@
import android.telephony.Rlog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.EncodeException;
import com.android.internal.telephony.GsmAlphabet;
import dalvik.annotation.compat.UnsupportedAppUsage;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.util.List;
/**
@@ -925,5 +927,32 @@
serializedFplmns[offset++] = (byte) 0xff;
}
return serializedFplmns;
+
+ }
+
+ static byte[]
+ stringToAdnStringField(String alphaTag) {
+ boolean isUcs2 = false;
+ try {
+ for(int i = 0; i < alphaTag.length(); i++) {
+ GsmAlphabet.countGsmSeptets(alphaTag.charAt(i), true);
+ }
+ } catch (EncodeException e) {
+ isUcs2 = true;
+ }
+ return stringToAdnStringField(alphaTag, isUcs2);
+ }
+
+ static byte[]
+ stringToAdnStringField(String alphaTag, boolean isUcs2) {
+ if (!isUcs2) {
+ return GsmAlphabet.stringToGsm8BitPacked(alphaTag);
+ }
+ byte[] alphaTagBytes = alphaTag.getBytes(Charset.forName("UTF-16BE"));
+ byte[] ret = new byte[1 + alphaTagBytes.length];
+ ret[0] = (byte)0x80;
+ System.arraycopy(alphaTagBytes, 0, ret, 1, alphaTagBytes.length);
+
+ return ret;
}
}
diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl
index b8d2971..200ae18 100644
--- a/wifi/java/android/net/wifi/ISoftApCallback.aidl
+++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl
@@ -41,4 +41,20 @@
* @param numClients number of connected clients
*/
void onNumClientsChanged(int numClients);
+
+ /**
+ * Service to manager callback providing Macaddress of connected stations.
+ *
+ * @param Macaddr Mac Address of connected clients
+ * @param numClients number of connected clients
+ */
+ void onStaConnected(String Macaddr, int numClients);
+
+ /**
+ * Service to manager callback providing Macaddress of disconnected stations.
+ *
+ * @param Macaddr Mac Address of disconnected clients
+ * @param numClients number of connected clients
+ */
+ void onStaDisconnected(String Macaddr, int numClients);
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1337739..5ab6678 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -37,6 +37,7 @@
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiDppConfig;
import android.net.wifi.WifiNetworkSuggestion;
import android.os.Messenger;
@@ -197,6 +198,34 @@
void unregisterTrafficStateCallback(int callbackIdentifier);
+ String getCapabilities(String capaType);
+
+ int dppAddBootstrapQrCode(String uri);
+
+ int dppBootstrapGenerate(in WifiDppConfig config);
+
+ String dppGetUri(int bootstrap_id);
+
+ int dppBootstrapRemove(int bootstrap_id);
+
+ int dppListen(String frequency, int dpp_role, boolean qr_mutual, boolean netrole_ap);
+
+ void dppStopListen();
+
+ int dppConfiguratorAdd(String curve, String key, int expiry);
+
+ int dppConfiguratorRemove(int config_id);
+
+ int dppStartAuth(in WifiDppConfig config);
+
+ String dppConfiguratorGetKey(int id);
+
+ boolean isExtendingWifi();
+
+ boolean isWifiCoverageExtendFeatureEnabled();
+
+ void enableWifiCoverageExtendFeature(boolean enable);
+
void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier);
void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
@@ -232,4 +261,6 @@
void registerScanResultsListener(in IBinder binder, in IScanResultsListener Listener, int listenerIdentifier);
void unregisterScanResultsListener(int listenerIdentifier);
+
+ int getSoftApWifiGeneration();
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index c0c0361..0761400 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -138,7 +138,7 @@
* Used for Hotspot 2.0.
*/
public static final int KEY_MGMT_OSEN = 7;
- /**
+ /**
* @hide
* Security key management scheme: SAE.
*/
@@ -165,6 +165,21 @@
public static final int KEY_MGMT_OWE_TRANSITION = 12;
/**
* @hide
+ * Security key management scheme: DPP.
+ */
+ public static final int KEY_MGMT_DPP = 13;
+ /**
+ * @hide
+ * Security key management scheme: FILS_SHA256.
+ */
+ public static final int KEY_MGMT_FILS_SHA256 = 14;
+ /**
+ * @hide
+ * Security key management scheme: FILS_SHA384.
+ */
+ public static final int KEY_MGMT_FILS_SHA384 = 15;
+ /**
+ * @hide
* No cipher suite.
*/
public static final int CIPHER_NONE = 0;
@@ -427,6 +442,21 @@
}
/**
+ * @hide
+ */
+ public boolean is60GHz() {
+ return ScanResult.is60GHz(frequency);
+ }
+
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public static boolean is60GHz(int freq) {
+ return freq >= 58320 && freq <= 70200;
+ }
+
+ /**
* @hide
* anqp lines from supplicant BSS response
*/
@@ -465,6 +495,8 @@
public static final int EID_VHT_OPERATION = 192;
@UnsupportedAppUsage
public static final int EID_VSA = 221;
+ public static final int EID_EXTENSION = 255;
+ public static final int EID_EXT_HE_CAPABILITIES = 35;
@UnsupportedAppUsage
public int id;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 2afb14a..b51622c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -95,6 +95,9 @@
/** {@hide} */
private static final int MAXIMUM_RANDOM_MAC_GENERATION_RETRY = 3;
+ /** {@hide} */
+ public static final String shareThisApVarName = "share_this_ap";
+
/**
* Recognized key management schemes.
*/
@@ -162,11 +165,29 @@
*/
public static final int WPA_EAP_SHA256 = 12;
+ /**
+ * IEEE 802.11ai FILS SK with SHA256
+ * @hide
+ */
+ public static final int FILS_SHA256 = 13;
+ /**
+ * IEEE 802.11ai FILS SK with SHA384:
+ * @hide
+ */
+ public static final int FILS_SHA384 = 14;
+ /**
+ * Device Provisioning Protocol
+ * @hide
+ */
+ public static final int DPP = 15;
+
public static final String varName = "key_mgmt";
public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
"IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
- "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
+ "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256",
+ "FILS_SHA256", "FILS_SHA384", "DPP",
+ };
}
/**
@@ -360,6 +381,10 @@
public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
/** @hide */
public static final int SECURITY_TYPE_OWE = 6;
+ /** @hide */
+ public static final int SECURITY_TYPE_FILS_SHA256 = 7;
+ /** @hide */
+ public static final int SECURITY_TYPE_FILS_SHA384 = 8;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -370,7 +395,9 @@
SECURITY_TYPE_EAP,
SECURITY_TYPE_SAE,
SECURITY_TYPE_EAP_SUITE_B,
- SECURITY_TYPE_OWE
+ SECURITY_TYPE_OWE,
+ SECURITY_TYPE_FILS_SHA256,
+ SECURITY_TYPE_FILS_SHA384
})
public @interface SecurityType {}
@@ -422,6 +449,12 @@
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
requirePMF = true;
break;
+ case SECURITY_TYPE_FILS_SHA256:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA256);
+ break;
+ case SECURITY_TYPE_FILS_SHA384:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.FILS_SHA384);
+ break;
default:
throw new IllegalArgumentException("unknown security type " + securityType);
}
@@ -474,6 +507,18 @@
public static final int AP_BAND_5GHZ = 1;
/**
+ * 2GHz + 5GHz Dual band.
+ * @hide
+ */
+ public static final int AP_BAND_DUAL = 2;
+
+ /**
+ * 60GHz band
+ * @hide
+ */
+ public static final int AP_BAND_60GHZ = 3;
+
+ /**
* Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
* operating country code and current radio conditions.
* @hide
@@ -558,6 +603,12 @@
public boolean requirePMF;
/**
+ * @hide
+ * This configuration is used in AP to extend the coverage.
+ */
+ public boolean shareThisAp;
+
+ /**
* Update identifier, for Passpoint network.
* @hide
*/
@@ -792,6 +843,12 @@
/**
* @hide
+ * Iface name for OWE transition mode
+ */
+ public String oweTransIfaceName;
+
+ /**
+ * @hide
* The WiFi configuration is considered to have no internet access for purpose of autojoining
* if there has been a report of it having no internet access, and, it never have had
* internet access in the past.
@@ -1079,6 +1136,29 @@
}
mRandomizedMacAddress = mac;
}
+ /**
+ * @hide
+ * DPP Connector (signedConnector as string).
+ */
+ public String dppConnector;
+
+ /**
+ * @hide
+ * DPP net Access Key (own private key).
+ */
+ public String dppNetAccessKey;
+
+ /**
+ * @hide
+ * DPP net Access Key expiry in UNIX time stamp. 0 indicates no expiration.
+ */
+ public int dppNetAccessKeyExpiry;
+
+ /**
+ * @hide
+ * DPP C-Sign key (Configurator public key).
+ */
+ public String dppCsign;
/** @hide
* Boost given to RSSI on a home network for the purpose of calculating the score
@@ -1758,6 +1838,7 @@
roamingConsortiumIds = new long[0];
priority = 0;
hiddenSSID = false;
+ shareThisAp = false;
allowedKeyManagement = new BitSet();
allowedProtocols = new BitSet();
allowedAuthAlgorithms = new BitSet();
@@ -1787,6 +1868,11 @@
shared = true;
dtimInterval = 0;
mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
+ dppConnector = null;
+ dppNetAccessKey = null;
+ dppNetAccessKeyExpiry = -1;
+ dppCsign = null;
+ oweTransIfaceName = null;
}
/**
@@ -1842,6 +1928,7 @@
.append(" PRIO: ").append(this.priority)
.append(" HIDDEN: ").append(this.hiddenSSID)
.append(" PMF: ").append(this.requirePMF)
+ .append(" OWE Transition mode Iface: ").append(this.oweTransIfaceName)
.append('\n');
@@ -1997,6 +2084,17 @@
sbuf.append("\nEnterprise config:\n");
sbuf.append(enterpriseConfig);
+ sbuf.append("\nDPP config:\n");
+ if (this.dppConnector != null) {
+ sbuf.append(" Dpp Connector: *\n");
+ }
+ if (this.dppNetAccessKey != null) {
+ sbuf.append(" Dpp NetAccessKey: *\n");
+ }
+ if (this.dppCsign != null) {
+ sbuf.append(" Dpp Csign: *\n");
+ }
+
sbuf.append("IP config:\n");
sbuf.append(mIpConfiguration.toString());
@@ -2039,6 +2137,9 @@
}
sbuf.append("recentFailure: ").append("Association Rejection code: ")
.append(recentFailure.getAssociationStatus()).append("\n");
+
+ sbuf.append("ShareThisAp: ").append(this.shareThisAp);
+ sbuf.append('\n');
return sbuf.toString();
}
@@ -2160,6 +2261,8 @@
return KeyMgmt.WPA_EAP;
} else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return KeyMgmt.IEEE8021X;
+ } else if (allowedKeyManagement.get(KeyMgmt.DPP)) {
+ return KeyMgmt.DPP;
} else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
return KeyMgmt.SAE;
} else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
@@ -2217,6 +2320,8 @@
key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
} else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+ } else if (allowedKeyManagement.get(KeyMgmt.DPP)) {
+ key = SSID + KeyMgmt.strings[KeyMgmt.DPP];
} else {
key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
}
@@ -2358,6 +2463,7 @@
SSID = source.SSID;
BSSID = source.BSSID;
FQDN = source.FQDN;
+ shareThisAp = source.shareThisAp;
roamingConsortiumIds = source.roamingConsortiumIds.clone();
providerFriendlyName = source.providerFriendlyName;
isHomeProviderNetwork = source.isHomeProviderNetwork;
@@ -2428,10 +2534,16 @@
shared = source.shared;
recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
mRandomizedMacAddress = source.mRandomizedMacAddress;
+ dppConnector = source.dppConnector;
+ dppNetAccessKey = source.dppNetAccessKey;
+ dppNetAccessKeyExpiry = source.dppNetAccessKeyExpiry;
+ dppCsign = source.dppCsign;
+
macRandomizationSetting = source.macRandomizationSetting;
randomizedMacLastModifiedTimeMs = source.randomizedMacLastModifiedTimeMs;
requirePMF = source.requirePMF;
updateIdentifier = source.updateIdentifier;
+ oweTransIfaceName = source.oweTransIfaceName;
}
}
@@ -2443,6 +2555,7 @@
mNetworkSelectionStatus.writeToParcel(dest);
dest.writeString(SSID);
dest.writeString(BSSID);
+ dest.writeInt(shareThisAp ? 1 : 0);
dest.writeInt(apBand);
dest.writeInt(apChannel);
dest.writeString(FQDN);
@@ -2502,9 +2615,14 @@
dest.writeString(mPasspointManagementObjectTree);
dest.writeInt(recentFailure.getAssociationStatus());
dest.writeParcelable(mRandomizedMacAddress, flags);
+ dest.writeString(dppConnector);
+ dest.writeString(dppNetAccessKey);
+ dest.writeInt(dppNetAccessKeyExpiry);
+ dest.writeString(dppCsign);
dest.writeInt(macRandomizationSetting);
dest.writeInt(osu ? 1 : 0);
dest.writeLong(randomizedMacLastModifiedTimeMs);
+ dest.writeString(oweTransIfaceName);
}
/** Implement the Parcelable interface {@hide} */
@@ -2518,6 +2636,7 @@
config.mNetworkSelectionStatus.readFromParcel(in);
config.SSID = in.readString();
config.BSSID = in.readString();
+ config.shareThisAp = in.readInt() != 0;
config.apBand = in.readInt();
config.apChannel = in.readInt();
config.FQDN = in.readString();
@@ -2577,9 +2696,14 @@
config.mPasspointManagementObjectTree = in.readString();
config.recentFailure.setAssociationStatus(in.readInt());
config.mRandomizedMacAddress = in.readParcelable(null);
+ config.dppConnector = in.readString();
+ config.dppNetAccessKey = in.readString();
+ config.dppNetAccessKeyExpiry = in.readInt();
+ config.dppCsign = in.readString();
config.macRandomizationSetting = in.readInt();
config.osu = in.readInt() != 0;
config.randomizedMacLastModifiedTimeMs = in.readLong();
+ config.oweTransIfaceName = in.readString();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiDppConfig.aidl b/wifi/java/android/net/wifi/WifiDppConfig.aidl
new file mode 100644
index 0000000..ac42fd9
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiDppConfig.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+parcelable WifiDppConfig;
+
diff --git a/wifi/java/android/net/wifi/WifiDppConfig.java b/wifi/java/android/net/wifi/WifiDppConfig.java
new file mode 100644
index 0000000..e41adcf
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiDppConfig.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** DPP configuration class
+ * @hide
+ */
+public class WifiDppConfig implements Parcelable {
+ private static final String TAG = "WifiDppConfig";
+ public static final int DPP_INVALID_CONFIG_ID = -1;
+ public static final int DPP_ROLE_CONFIGURATOR = 0;
+ public static final int DPP_ROLE_ENROLLEE = 1;
+ public static final int DPP_TYPE_QR_CODE = 0;
+ public static final int DPP_TYPE_NAN_BOOTSTRAP = 1;
+ public int peer_bootstrap_id;
+ public int own_bootstrap_id;
+ public int dpp_role;
+ public String ssid;
+ public String passphrase;
+ public int isAp;
+ public int isDpp;
+ public int conf_id;
+ public int bootstrap_type;
+ public String chan_list;
+ public String mac_addr;
+ public String info;
+ public String curve;
+ public int expiry;
+ public String key;
+
+ private DppResult mEventResult = new DppResult();
+
+ public WifiDppConfig() {
+ peer_bootstrap_id = DPP_INVALID_CONFIG_ID;
+ own_bootstrap_id = DPP_INVALID_CONFIG_ID;
+ dpp_role = DPP_INVALID_CONFIG_ID;
+ isAp = DPP_INVALID_CONFIG_ID;
+ isDpp = DPP_INVALID_CONFIG_ID;
+ conf_id = DPP_INVALID_CONFIG_ID;
+ bootstrap_type = DPP_INVALID_CONFIG_ID;
+ expiry = 0;
+ ssid = null;
+ passphrase = null;
+ chan_list = null;
+ mac_addr = null;
+ info = null;
+ curve = null;
+ key = null;
+ }
+
+ public DppResult getDppResult() {
+ return mEventResult;
+ }
+
+ public void setDppResult(DppResult result) {
+ mEventResult = result;
+ }
+
+ public void writeToParcel(Parcel dest) {
+ }
+
+ public void readFromParcel(Parcel in) {
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(peer_bootstrap_id);
+ dest.writeInt(own_bootstrap_id);
+ dest.writeInt(dpp_role);
+ dest.writeString(ssid);
+ dest.writeString(passphrase);
+ dest.writeInt(isAp);
+ dest.writeInt(isDpp);
+ dest.writeInt(conf_id);
+ dest.writeInt(bootstrap_type);
+ dest.writeString(chan_list);
+ dest.writeString(mac_addr);
+ dest.writeString(info);
+ dest.writeString(curve);
+ dest.writeInt(expiry);
+ dest.writeString(key);
+ mEventResult.writeToParcel(dest);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WifiDppConfig> CREATOR =
+ new Creator<WifiDppConfig>() {
+ public WifiDppConfig createFromParcel(Parcel in) {
+ WifiDppConfig config = new WifiDppConfig();
+ config.peer_bootstrap_id = in.readInt();
+ config.own_bootstrap_id = in.readInt();
+ config.dpp_role = in.readInt();
+ config.ssid = in.readString();
+ config.passphrase = in.readString();
+ config.isAp = in.readInt();
+ config.isDpp = in.readInt();
+ config.conf_id = in.readInt();
+ config.bootstrap_type = in.readInt();
+ config.chan_list = in.readString();
+ config.mac_addr = in.readString();
+ config.info = in.readString();
+ config.curve = in.readString();
+ config.expiry = in.readInt();
+ config.key = in.readString();
+ config.mEventResult.readFromParcel(in);
+ return config;
+ }
+ public WifiDppConfig[] newArray(int size) {
+ return new WifiDppConfig[size];
+ }
+ };
+ /**
+ * Stores supplicant state change information passed from WifiMonitor to
+ * a state machine. WifiStateMachine, SupplicantStateTracker and WpsStateMachine
+ * are example state machines that handle it.
+ * @hide
+ */
+ public static class DppResult {
+
+ public boolean initiator;
+ public int netID;
+ public byte capab;
+ public byte authMissingParam;
+ public byte configEventType;
+ public String iBootstrapData;
+ public String ssid;
+ public String connector;
+ public String cSignKey;
+ public String netAccessKey;
+ public int netAccessKeyExpiry;
+ public String passphrase;
+ public String psk;
+
+ public static final int DPP_EVENT_AUTH_SUCCESS = 0;
+ public static final int DPP_EVENT_NOT_COMPATIBLE = 1;
+ public static final int DPP_EVENT_RESPONSE_PENDING = 2;
+ public static final int DPP_EVENT_SCAN_PEER_QRCODE = 3;
+ public static final int DPP_EVENT_CONF = 4;
+ public static final int DPP_EVENT_MISSING_AUTH = 5;
+ public static final int DPP_EVENT_NETWORK_ID = 6;
+
+
+ public static final int DPP_CONF_EVENT_TYPE_FAILED = 0;
+ public static final int DPP_CONF_EVENT_TYPE_SENT = 1;
+ public static final int DPP_CONF_EVENT_TYPE_RECEIVED = 2;
+
+ public DppResult() {
+ this.initiator = false;
+ this.netID = -1;
+ this.capab = 0;
+ this.authMissingParam = 0;
+ this.configEventType = 0;
+ this.iBootstrapData = null;
+ this.ssid = null;
+ this.connector = null;
+ this.cSignKey = null;
+ this.netAccessKey = null;
+ this.netAccessKeyExpiry = 0;
+ this.passphrase = null;
+ this.psk = null;
+ }
+
+ public void writeToParcel(Parcel dest) {
+ dest.writeInt(initiator ? 1 : 0);
+ dest.writeInt(netID);
+ dest.writeByte(capab);
+ dest.writeByte(authMissingParam);
+ dest.writeByte(configEventType);
+ dest.writeString(iBootstrapData);
+ dest.writeString(ssid);
+ dest.writeString(connector);
+ dest.writeString(cSignKey);
+ dest.writeString(netAccessKey);
+ dest.writeInt(netAccessKeyExpiry);
+ dest.writeString(passphrase);
+ dest.writeString(psk);
+ }
+
+ public void readFromParcel(Parcel in) {
+ this.initiator = (in.readInt() > 0) ? true : false;
+ this.netID = in.readInt();
+ this.capab = in.readByte();
+ this.authMissingParam = in.readByte();
+ this.configEventType = in.readByte();
+ this.iBootstrapData = in.readString();
+ this.ssid = in.readString();
+ this.connector = in.readString();
+ this.cSignKey = in.readString();
+ this.netAccessKey = in.readString();
+ this.netAccessKeyExpiry = in.readInt();
+ this.passphrase = in.readString();
+ this.psk = in.readString();
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index f8c2011..4b7af5a 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -60,6 +60,11 @@
public static final String DOM_SUFFIX_MATCH_KEY = "domain_suffix_match";
/** @hide */
public static final String OPP_KEY_CACHING = "proactive_key_caching";
+ /** @hide */
+ public static final String EAP_ERP = "eap_erp";
+ /** @hide */
+ public static final String KEY_SIMNUM = "sim_num";
+
/**
* String representing the keystore OpenSSL ENGINE's ID.
* @hide
@@ -175,7 +180,8 @@
/**
* Fields that have unquoted values in {@link #mFields}.
*/
- private static final List<String> UNQUOTED_KEYS = Arrays.asList(ENGINE_KEY, OPP_KEY_CACHING);
+ private static final List<String> UNQUOTED_KEYS = Arrays.asList(ENGINE_KEY, OPP_KEY_CACHING,
+ EAP_ERP);
@UnsupportedAppUsage
private HashMap<String, String> mFields = new HashMap<String, String>();
@@ -492,6 +498,15 @@
}
}
+ /** @hide */
+ public void setSimNum(int SIMNum) {
+ setFieldValue(KEY_SIMNUM, Integer.toString(SIMNum));
+ }
+
+ /** @hide */
+ public String getSimNum() {
+ return getFieldValue(KEY_SIMNUM);
+ }
/**
* Get the eap method.
* @return eap method configured
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 62ba95d..7eadd3b 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -256,6 +256,14 @@
*/
private boolean mMeteredHint;
+
+ private int mWifiGeneration;
+
+ private boolean mVhtMax8SpatialStreamsSupport;
+
+ private boolean mTwtSupport;
+
+
/** @hide */
@UnsupportedAppUsage
public WifiInfo() {
@@ -266,6 +274,7 @@
mRssi = INVALID_RSSI;
mLinkSpeed = LINK_SPEED_UNKNOWN;
mFrequency = -1;
+ mWifiGeneration = -1;
}
/** @hide */
@@ -285,6 +294,9 @@
setNetworkSuggestionOrSpecifierPackageName(null);
setFQDN(null);
setProviderFriendlyName(null);
+ setWifiGeneration(-1);
+ setTwtSupport(false);
+ setVhtMax8SpatialStreamsSupport(false);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -321,6 +333,9 @@
mOsuAp = source.mOsuAp;
mFqdn = source.mFqdn;
mProviderFriendlyName = source.mProviderFriendlyName;
+ mWifiGeneration = source.mWifiGeneration;
+ mVhtMax8SpatialStreamsSupport = source.mVhtMax8SpatialStreamsSupport;
+ mTwtSupport = source.mTwtSupport;
txBad = source.txBad;
txRetries = source.txRetries;
txSuccess = source.txSuccess;
@@ -719,6 +734,36 @@
}
}
+ /** @hide */
+ public void setWifiGeneration(int generation) {
+ mWifiGeneration = generation;
+ }
+
+ /** @hide */
+ public int getWifiGeneration() {
+ return mWifiGeneration;
+ }
+
+ /** @hide */
+ public void setVhtMax8SpatialStreamsSupport(boolean vhtMax8SpatialStreamsSupport) {
+ mVhtMax8SpatialStreamsSupport = vhtMax8SpatialStreamsSupport;
+ }
+
+ /** @hide */
+ public boolean isVhtMax8SpatialStreamsSupported() {
+ return mVhtMax8SpatialStreamsSupport;
+ }
+
+ /** @hide */
+ public void setTwtSupport(boolean twtSupport) {
+ mTwtSupport = twtSupport;
+ }
+
+ /** @hide */
+ public boolean isTwtSupported() {
+ return mTwtSupport;
+ }
+
/** {@hide} */
@UnsupportedAppUsage
public static String removeDoubleQuotes(String string) {
@@ -740,6 +785,9 @@
.append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
.append(", Supplicant state: ")
.append(mSupplicantState == null ? none : mSupplicantState)
+ .append(", Wifi Generation: ").append(mWifiGeneration)
+ .append(", TWT support: ").append(mTwtSupport)
+ .append(", Eight Max VHT Spatial streams support: ").append(mVhtMax8SpatialStreamsSupport)
.append(", Wi-Fi technology: ").append(mWifiTechnology)
.append(", RSSI: ").append(mRssi)
.append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
@@ -796,6 +844,9 @@
dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
dest.writeString(mFqdn);
dest.writeString(mProviderFriendlyName);
+ dest.writeInt(mWifiGeneration);
+ dest.writeInt(mVhtMax8SpatialStreamsSupport ? 1 : 0);
+ dest.writeInt(mTwtSupport ? 1 : 0);
dest.writeInt(mWifiTechnology);
}
@@ -838,6 +889,9 @@
info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
info.mFqdn = in.readString();
info.mProviderFriendlyName = in.readString();
+ info.mWifiGeneration = in.readInt();
+ info.mVhtMax8SpatialStreamsSupport = in.readInt() != 0;
+ info.mTwtSupport = in.readInt() != 0;
info.mWifiTechnology = in.readInt();
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 04b073b..6d382ee 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -219,6 +219,19 @@
public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
/**
+ *
+ *
+ * @hide
+ **/
+ public static final String WIFI_DATA_STALL = "com.qualcomm.qti.net.wifi.WIFI_DATA_STALL";
+
+ /**
+ *
+ * see data stall reason code
+ * @hide
+ **/
+ public static final String EXTRA_WIFI_DATA_STALL_REASON = "data_stall_reasoncode";
+ /**
* Broadcast intent action indicating that the credential of a Wi-Fi network
* has been changed. One extra provides the ssid of the network. Another
* extra provides the event type, whether the credential is saved or forgot.
@@ -521,6 +534,21 @@
*/
public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
/**
+ * The look up key for a string that gives additonal info about EXTRA_WIFI_AP_FAILURE_REASON
+ * currently support no_5ghz_support
+ * @see #WIFI_AP_FAILURE_DESC_NO_5GHZ_SUPPORT
+ *
+ * @hide
+ */
+ public static final String EXTRA_WIFI_AP_FAILURE_DESCRIPTION = "wifi_ap_error_description";
+ /**
+ * If Wi-Fi AP start failed with SAP_START_FAILURE_NO_CHANNEL reason code and has this
+ * description means that no supported channel exists on 5G band
+ *
+ * @hide
+ */
+ public static final String WIFI_AP_FAILURE_DESC_NO_5GHZ_SUPPORT = "wifi_ap_error_no_5g_support";
+ /**
* The previous Wi-Fi state.
*
* @see #EXTRA_WIFI_AP_STATE
@@ -927,6 +955,26 @@
public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
/**
+ * Broadcast intent action indicating DPP Event arrival notificaiton.
+ * @see #EXTRA_DPP_DATA.
+ * @hide
+ */
+ public static final String DPP_EVENT_ACTION = "com.qualcomm.qti.net.wifi.DPP_EVENT";
+
+ /**
+ * This shall point to DppResult Type.
+ * @hide
+ */
+ public static final String EXTRA_DPP_EVENT_TYPE = "dppEventType";
+
+ /**
+ * This shall point to WifiDppConfig object. Retrieve with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
+ */
+ public static final String EXTRA_DPP_EVENT_DATA = "dppEventData";
+
+ /**
* Activity Action: Show a system activity that allows the user to enable
* scans to be available even with Wi-Fi turned off.
*
@@ -972,6 +1020,34 @@
public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
/**
+ * Broadcast intent action indicating that WifiCountryCode was updated with new
+ * country code.
+ *
+ * @see #EXTRA_COUNTRY_CODE
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String WIFI_COUNTRY_CODE_CHANGED_ACTION =
+ "android.net.wifi.COUNTRY_CODE_CHANGED";
+
+ /**
+ * The lookup key for a string that indicates the 2 char new country code
+ *
+ * @hide
+ */
+ public static final String EXTRA_COUNTRY_CODE = "country_code";
+
+ /**
+ * Broadcast intent action indicating that the user initiated Wifi OFF
+ * or APM ON and Wifi disconnection is in progress
+ * Actual Wifi disconnection happens after mDisconnectDelayDuration seconds.
+ * @hide
+ */
+ public static final String ACTION_WIFI_DISCONNECT_IN_PROGRESS =
+ "com.qualcomm.qti.net.wifi.WIFI_DISCONNECT_IN_PROGRESS";
+
+ /**
* Directed broadcast intent action indicating that the device has connected to one of the
* network suggestions provided by the app. This will be sent post connection to a network
* which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
@@ -1140,6 +1216,16 @@
@GuardedBy("mLock")
private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
+ /* Wi-Fi generation codes */
+ /** @hide */
+ public static final int WIFI_GENERATION_DEFAULT = 0;
+ /** @hide */
+ public static final int WIFI_GENERATION_4 = 4;
+ /** @hide */
+ public static final int WIFI_GENERATION_5 = 5;
+ /** @hide */
+ public static final int WIFI_GENERATION_6 = 6;
+
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
@@ -1425,6 +1511,76 @@
return addOrUpdateNetwork(config);
}
+
+ /**
+ * Check the WifiSharing mode.
+ *
+ * @return true if Current Sta network connected with extending coverage
+ * option. false if it is not.
+ *
+ * @hide no intent to publish
+ */
+ public boolean isExtendingWifi() {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return false;
+ return iWifiManager.isExtendingWifi();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Check Wifi coverage extend feature enabled or not.
+ *
+ * @return true if Wifi extend feature is enabled.
+ *
+ * @hide no intent to publish
+ */
+ public boolean isWifiCoverageExtendFeatureEnabled() {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return false;
+ return iWifiManager.isWifiCoverageExtendFeatureEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enable/disable Wifi coverage extend feature.
+ *
+ * @hide no intent to publish
+ */
+ public void enableWifiCoverageExtendFeature(boolean enable) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) {
+ throw new RemoteException("Wifi service is not running");
+ }
+ iWifiManager.enableWifiCoverageExtendFeature(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get SoftAp Wi-Fi generation.
+ *
+ * @return Wi-Fi generation if SoftAp enabled or -1.
+ *
+ * @hide no intent to publish
+ */
+ public int getSoftApWifiGeneration() {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.getSoftApWifiGeneration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Internal method for doing the RPC that creates a new network description
* or updates an existing one.
@@ -2440,6 +2596,7 @@
* in order to get valid results.
*/
public List<ScanResult> getScanResults() {
+ android.util.SeempLog.record(55);
try {
IWifiManager iWifiManager = getIWifiManager();
if (iWifiManager == null) return Collections.emptyList();
@@ -3265,6 +3422,22 @@
* @param numClients number of connected clients
*/
public abstract void onNumClientsChanged(int numClients);
+
+ /**
+ * Called when Stations connected to soft AP.
+ *
+ * @param Macaddr Mac Address of connected Stations to soft AP
+ * @param numClients number of connected clients
+ */
+ public abstract void onStaConnected(String Macaddr, int numClients);
+
+ /**
+ * Called when Stations disconnected to soft AP.
+ *
+ * @param Macaddr Mac Address of Disconnected Stations to soft AP
+ * @param numClients number of connected clients
+ */
+ public abstract void onStaDisconnected(String Macaddr, int numClients);
}
/**
@@ -3301,6 +3474,22 @@
mCallback.onNumClientsChanged(numClients);
});
}
+
+ @Override
+ public void onStaConnected(String Macaddr, int numClients) throws RemoteException {
+ Log.v(TAG, "SoftApCallbackProxy: [" + numClients + "]onStaConnected Macaddr =" + Macaddr);
+ mHandler.post(() -> {
+ mCallback.onStaConnected(Macaddr, numClients);
+ });
+ }
+
+ @Override
+ public void onStaDisconnected(String Macaddr, int numClients) throws RemoteException {
+ Log.v(TAG, "SoftApCallbackProxy: [" + numClients + "]onStaDisconnected Macaddr =" + Macaddr);
+ mHandler.post(() -> {
+ mCallback.onStaDisconnected(Macaddr, numClients);
+ });
+ }
}
/**
@@ -4579,7 +4768,6 @@
mExecutor = executor;
mCallback = callback;
}
-
@Override
public void onProvisioningStatus(int status) {
mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
@@ -4718,6 +4906,215 @@
}
/**
+ * Get driver Capabilities.
+ *
+ * @param capaType ASCII string, capability type ex: key_mgmt.
+ * @return String of capabilities from driver for type capaParameter.
+ * {@hide}
+ */
+ public String getCapabilities(String capaType) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return "";
+ return iWifiManager.getCapabilities(capaType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Add the DPP bootstrap info obtained from QR code.
+ *
+ * @param uri:The URI obtained from the QR code reader.
+ *
+ * @return: Handle to strored info else -1 on failure
+ * @hide
+ */
+ public int dppAddBootstrapQrCode(String uri) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppAddBootstrapQrCode(uri);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Generate bootstrap URI based on the passed arguments
+ *
+ * @param config – bootstrap generate config, mandatory parameters
+ * are: type, frequency, mac_addr, curve, key.
+ *
+ * @return: Handle to strored URI info else -1 on failure
+ * @hide
+ */
+ public int dppBootstrapGenerate(WifiDppConfig config) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppBootstrapGenerate(config);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get bootstrap URI based on bootstrap ID
+ *
+ * @param bootstrap_id: Stored bootstrap ID
+ *
+ * @return: URI string else -1 on failure
+ * @hide
+ */
+ public String dppGetUri(int bootstrap_id) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return "-1";
+ return iWifiManager.dppGetUri(bootstrap_id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove bootstrap URI based on bootstrap ID.
+ *
+ * @param bootstrap_id: Stored bootstrap ID. 0 to remove all.
+ *
+ * @return: 0 – Success or -1 on failure
+ * @hide
+ */
+ public int dppBootstrapRemove(int bootstrap_id) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppBootstrapRemove(bootstrap_id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * start listen on the channel specified waiting to receive
+ * the DPP Authentication request.
+ *
+ * @param frequency: DPP listen frequency
+ * @param dpp_role: Configurator/Enrollee role
+ * @param qr_mutual: Mutual authentication required
+ * @param netrole_ap: network role
+ *
+ * @return: Returns 0 if a DPP-listen work is successfully
+ * queued and -1 on failure.
+ * @hide
+ */
+ public int dppListen(String frequency, int dpp_role, boolean qr_mutual,
+ boolean netrole_ap) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppListen(frequency, dpp_role, qr_mutual, netrole_ap);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * stop ongoing dpp listen.
+ *
+ * @hide
+ */
+ public void dppStopListen() {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) {
+ throw new RemoteException("Wifi service is not running");
+ }
+ iWifiManager.dppStopListen();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adds the DPP configurator
+ *
+ * @param curve curve used for dpp encryption
+ * @param key private key
+ * @param expiry timeout in seconds
+ *
+ * @return: Identifier of the added configurator or -1 on failure
+ * @hide
+ */
+ public int dppConfiguratorAdd(String curve, String key, int expiry) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppConfiguratorAdd(curve, key, expiry);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Remove the added configurator through dppConfiguratorAdd.
+ *
+ * @param config_id: DPP Configurator ID. 0 to remove all.
+ *
+ * @return: Handle to strored info else -1 on failure
+ * @hide
+ */
+ public int dppConfiguratorRemove(int config_id) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppConfiguratorRemove(config_id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Start DPP authentication and provisioning with the specified peer
+ *
+ * @param config – dpp auth init config mandatory parameters
+ * are: peer_bootstrap_id, own_bootstrap_id, dpp_role,
+ * ssid, passphrase, isDpp, conf_id, expiry.
+ *
+ * @return: 0 if DPP auth request was transmitted and -1 on failure
+ * @hide
+ */
+ public int dppStartAuth(WifiDppConfig config) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return -1;
+ return iWifiManager.dppStartAuth(config);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Retrieve Private key to be used for configurator
+ *
+ * @param id: id of configurator
+ *
+ * @return: KEY string else -1 on failure
+ * @hide
+ */
+ public String dppConfiguratorGetKey(int id) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) return "-1";
+ return iWifiManager.dppConfiguratorGetKey(id);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @return true if this device supports WPA3-Personal SAE
*/
public boolean isWpa3SaeSupported() {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index c5318a9..b75e14f 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -141,7 +141,8 @@
"config_methods=(0x[0-9a-fA-F]+) " +
"dev_capab=(0x[0-9a-fA-F]+) " +
"group_capab=(0x[0-9a-fA-F]+)" +
- "( wfd_dev_info=0x([0-9a-fA-F]{12}))?"
+ "( wfd_dev_info=0x([0-9a-fA-F]{12}))?" +
+ "( wfd_r2_dev_info=0x([0-9a-fA-F]{4}))?"
);
/** 2 token device address pattern
@@ -228,6 +229,10 @@
wfdInfo = new WifiP2pWfdInfo(parseHex(str.substring(0,4)),
parseHex(str.substring(4,8)),
parseHex(str.substring(8,12)));
+ if (match.group(11) != null) {
+ String r2str = match.group(12);
+ wfdInfo.setWfdR2Device(parseHex(r2str.substring(0,4)));
+ }
}
break;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index d37c4a2..ef10092 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -556,27 +556,34 @@
public static final int SET_ONGOING_PEER_CONFIG_SUCCEEDED = BASE + 89;
/** @hide */
- public static final int REQUEST_P2P_STATE = BASE + 90;
+ public static final int SET_WFDR2_INFO = BASE + 90;
/** @hide */
- public static final int RESPONSE_P2P_STATE = BASE + 91;
+ public static final int SET_WFDR2_INFO_FAILED = BASE + 91;
+ /** @hide */
+ public static final int SET_WFDR2_INFO_SUCCEEDED = BASE + 92;
/** @hide */
- public static final int REQUEST_DISCOVERY_STATE = BASE + 92;
+ public static final int REQUEST_P2P_STATE = BASE + 93;
/** @hide */
- public static final int RESPONSE_DISCOVERY_STATE = BASE + 93;
+ public static final int RESPONSE_P2P_STATE = BASE + 94;
/** @hide */
- public static final int REQUEST_NETWORK_INFO = BASE + 94;
+ public static final int REQUEST_DISCOVERY_STATE = BASE + 95;
/** @hide */
- public static final int RESPONSE_NETWORK_INFO = BASE + 95;
+ public static final int RESPONSE_DISCOVERY_STATE = BASE + 96;
/** @hide */
- public static final int UPDATE_CHANNEL_INFO = BASE + 96;
+ public static final int REQUEST_NETWORK_INFO = BASE + 97;
+ /** @hide */
+ public static final int RESPONSE_NETWORK_INFO = BASE + 98;
/** @hide */
- public static final int REQUEST_DEVICE_INFO = BASE + 97;
+ public static final int UPDATE_CHANNEL_INFO = BASE + 99;
+
/** @hide */
- public static final int RESPONSE_DEVICE_INFO = BASE + 98;
+ public static final int REQUEST_DEVICE_INFO = BASE + 100;
+ /** @hide */
+ public static final int RESPONSE_DEVICE_INFO = BASE + 101;
/**
* Create a new WifiP2pManager instance. Applications use
@@ -928,6 +935,7 @@
case SET_DEVICE_NAME_FAILED:
case DELETE_PERSISTENT_GROUP_FAILED:
case SET_WFD_INFO_FAILED:
+ case SET_WFDR2_INFO_FAILED:
case START_WPS_FAILED:
case START_LISTEN_FAILED:
case STOP_LISTEN_FAILED:
@@ -956,6 +964,7 @@
case SET_DEVICE_NAME_SUCCEEDED:
case DELETE_PERSISTENT_GROUP_SUCCEEDED:
case SET_WFD_INFO_SUCCEEDED:
+ case SET_WFDR2_INFO_SUCCEEDED:
case START_WPS_SUCCEEDED:
case START_LISTEN_SUCCEEDED:
case STOP_LISTEN_SUCCEEDED:
@@ -1636,7 +1645,18 @@
c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
}
-
+ /** @hide */
+ public void setWFDR2Info(
+ Channel c, WifiP2pWfdInfo wfdInfo,
+ ActionListener listener) {
+ checkChannel(c);
+ try {
+ mService.checkConfigureWifiDisplayPermission();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ c.mAsyncChannel.sendMessage(SET_WFDR2_INFO, 0, c.putListener(listener), wfdInfo);
+ }
/**
* Delete a stored persistent group from the system settings.
*
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index 3caa280..39937f9 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -35,6 +35,8 @@
private int mDeviceInfo;
+ private int mR2DeviceInfo;
+
public static final int WFD_SOURCE = 0;
public static final int PRIMARY_SINK = 1;
public static final int SECONDARY_SINK = 2;
@@ -65,6 +67,7 @@
mDeviceInfo = devInfo;
mCtrlPort = ctrlPort;
mMaxThroughput = maxTput;
+ mR2DeviceInfo = -1;
}
@UnsupportedAppUsage
@@ -72,11 +75,19 @@
return mWfdEnabled;
}
+ public boolean isWfdR2Supported() {
+ return (mR2DeviceInfo<0?false:true);
+ }
+
@UnsupportedAppUsage
public void setWfdEnabled(boolean enabled) {
mWfdEnabled = enabled;
}
+ public void setWfdR2Device(int r2DeviceInfo) {
+ mR2DeviceInfo = r2DeviceInfo;
+ }
+
@UnsupportedAppUsage
public int getDeviceType() {
return (mDeviceInfo & DEVICE_TYPE);
@@ -153,12 +164,17 @@
Locale.US, "%04x%04x%04x", mDeviceInfo, mCtrlPort, mMaxThroughput);
}
+ public String getR2DeviceInfoHex() {
+ return String.format(
+ Locale.US, "%04x%04x", 2, mR2DeviceInfo);
+ }
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("WFD enabled: ").append(mWfdEnabled);
sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo);
sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort);
sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput);
+ sbuf.append("\n WFD R2 DeviceInfo: ").append(mR2DeviceInfo);
return sbuf.toString();
}
@@ -175,6 +191,7 @@
mDeviceInfo = source.mDeviceInfo;
mCtrlPort = source.mCtrlPort;
mMaxThroughput = source.mMaxThroughput;
+ mR2DeviceInfo = source.mR2DeviceInfo;
}
}
@@ -184,6 +201,7 @@
dest.writeInt(mDeviceInfo);
dest.writeInt(mCtrlPort);
dest.writeInt(mMaxThroughput);
+ dest.writeInt(mR2DeviceInfo);
}
public void readFromParcel(Parcel in) {
@@ -191,6 +209,7 @@
mDeviceInfo = in.readInt();
mCtrlPort = in.readInt();
mMaxThroughput = in.readInt();
+ mR2DeviceInfo = in.readInt();
}
/** Implement the Parcelable interface */
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 94fb5ae..300f1a2 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -34,6 +34,7 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiDppConfig;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiNetworkSuggestion;
import android.net.wifi.hotspot2.IProvisioningCallback;
@@ -473,6 +474,11 @@
}
@Override
+ public void enableWifiCoverageExtendFeature(boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void stopDppSession() throws RemoteException {
throw new UnsupportedOperationException();
}
@@ -527,4 +533,74 @@
public void unregisterScanResultsListener(int listenerIdentifier) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public boolean isWifiCoverageExtendFeatureEnabled() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isExtendingWifi() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCapabilities(String capaType) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppAddBootstrapQrCode(String uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppBootstrapGenerate(WifiDppConfig config) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String dppGetUri(int bootstrap_id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppBootstrapRemove(int bootstrap_id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppListen(String frequency, int dpp_role, boolean qr_mutual, boolean netrole_ap) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void dppStopListen() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppConfiguratorAdd(String curve, String key, int expiry) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppConfiguratorRemove(int config_id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int dppStartAuth(WifiDppConfig config) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String dppConfiguratorGetKey(int id) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getSoftApWifiGeneration() {
+ throw new UnsupportedOperationException();
+ }
}