Merge "MediaSessionService: Nullify the media button sesison when it's removed" into oc-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 84b9da9..d18006c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -34360,6 +34360,7 @@
method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
method public static void verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File) throws java.security.GeneralSecurityException, java.io.IOException;
+ method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
}
public static abstract interface RecoverySystem.ProgressListener {
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 5f66abd..447f280 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,8 @@
package android.os;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import android.annotation.SystemApi;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -24,9 +26,12 @@
import android.text.TextUtils;
import android.util.Log;
+import libcore.io.Streams;
+
import java.io.ByteArrayInputStream;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
@@ -39,6 +44,7 @@
import java.security.SignatureException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
@@ -46,6 +52,7 @@
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
import com.android.internal.logging.MetricsLogger;
@@ -317,6 +324,70 @@
} finally {
raf.close();
}
+
+ // Additionally verify the package compatibility.
+ if (!readAndVerifyPackageCompatibilityEntry(packageFile)) {
+ throw new SignatureException("package compatibility verification failed");
+ }
+ }
+
+ /**
+ * Verifies the compatibility entry from an {@link InputStream}.
+ *
+ * @return the verification result.
+ */
+ private static boolean verifyPackageCompatibility(InputStream inputStream) throws IOException {
+ ArrayList<String> list = new ArrayList<>();
+ ZipInputStream zis = new ZipInputStream(inputStream);
+ ZipEntry entry;
+ while ((entry = zis.getNextEntry()) != null) {
+ long entrySize = entry.getSize();
+ if (entrySize > Integer.MAX_VALUE || entrySize < 0) {
+ throw new IOException(
+ "invalid entry size (" + entrySize + ") in the compatibility file");
+ }
+ byte[] bytes = new byte[(int) entrySize];
+ Streams.readFully(zis, bytes);
+ list.add(new String(bytes, UTF_8));
+ }
+ if (list.isEmpty()) {
+ throw new IOException("no entries found in the compatibility file");
+ }
+ return (VintfObject.verify(list.toArray(new String[list.size()])) == 0);
+ }
+
+ /**
+ * Reads and verifies the compatibility entry in an OTA zip package. The compatibility entry is
+ * a zip file (inside the OTA package zip).
+ *
+ * @return {@code true} if the entry doesn't exist or verification passes.
+ */
+ private static boolean readAndVerifyPackageCompatibilityEntry(File packageFile)
+ throws IOException {
+ try (ZipFile zip = new ZipFile(packageFile)) {
+ ZipEntry entry = zip.getEntry("compatibility.zip");
+ if (entry == null) {
+ return true;
+ }
+ InputStream inputStream = zip.getInputStream(entry);
+ return verifyPackageCompatibility(inputStream);
+ }
+ }
+
+ /**
+ * Verifies the package compatibility info against the current system.
+ *
+ * @param compatibilityFile the {@link File} that contains the package compatibility info.
+ * @throws IOException if there were any errors reading the compatibility file.
+ * @return the compatibility verification result.
+ *
+ * {@hide}
+ */
+ @SystemApi
+ public static boolean verifyPackageCompatibility(File compatibilityFile) throws IOException {
+ try (InputStream inputStream = new FileInputStream(compatibilityFile)) {
+ return verifyPackageCompatibility(inputStream);
+ }
}
/**
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 4a9a2c5..c1f443f 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -35,6 +35,7 @@
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -89,6 +90,11 @@
// example: fs_stat,/dev/block/platform/soc/by-name/userdata,0x5
private static final String FS_STAT_PATTERN = "fs_stat,[^,]*/([^/,]+),(0x[0-9a-fA-F]+)";
+ private static final int FS_STAT_FS_FIXED = 0x400; // should match with fs_mgr.cpp:FsStatFlags
+ private static final String FSCK_PASS_PATTERN = "Pass ([1-9]E?):";
+ private static final String FSCK_TREE_OPTIMIZATION_PATTERN =
+ "Inode [0-9]+ extent tree.*could be shorter";
+ private static final String FSCK_FS_MODIFIED = "FILE SYSTEM WAS MODIFIED";
// ro.boottime.init.mount_all. + postfix for mount_all duration
private static final String[] MOUNT_DURATION_PROPS_POSTFIX =
new String[] { "early", "default", "late" };
@@ -334,17 +340,22 @@
String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
Pattern pattern = Pattern.compile(FS_STAT_PATTERN);
- for (String line : log.split("\n")) { // should check all lines
- if (line.contains("FILE SYSTEM WAS MODIFIED")) {
+ String lines[] = log.split("\n");
+ int lineNumber = 0;
+ int lastFsStatLineNumber = 0;
+ for (String line : lines) { // should check all lines
+ if (line.contains(FSCK_FS_MODIFIED)) {
uploadNeeded = true;
} else if (line.contains("fs_stat")){
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
- handleFsckFsStat(matcher);
+ handleFsckFsStat(matcher, lines, lastFsStatLineNumber, lineNumber);
+ lastFsStatLineNumber = lineNumber;
} else {
Slog.w(TAG, "cannot parse fs_stat:" + line);
}
}
+ lineNumber++;
}
if (uploadEnabled && uploadNeeded ) {
@@ -403,7 +414,88 @@
}
}
- private static void handleFsckFsStat(Matcher match) {
+ /**
+ * Fix fs_stat from e2fsck.
+ * For now, only handle the case of quota warning caused by tree optimization. Clear fs fix
+ * flag (=0x400) caused by that.
+ *
+ * @param partition partition name
+ * @param statOrg original stat reported from e2fsck log
+ * @param lines e2fsck logs broken down into lines
+ * @param startLineNumber start line to parse
+ * @param endLineNumber end line. exclusive.
+ * @return updated fs_stat. For tree optimization, will clear bit 0x400.
+ */
+ @VisibleForTesting
+ public static int fixFsckFsStat(String partition, int statOrg, String[] lines,
+ int startLineNumber, int endLineNumber) {
+ int stat = statOrg;
+ if ((stat & FS_STAT_FS_FIXED) != 0) {
+ // fs was fixed. should check if quota warning was caused by tree optimization.
+ // This is not a real fix but optimization, so should not be counted as a fs fix.
+ Pattern passPattern = Pattern.compile(FSCK_PASS_PATTERN);
+ Pattern treeOptPattern = Pattern.compile(FSCK_TREE_OPTIMIZATION_PATTERN);
+ String currentPass = "";
+ boolean foundTreeOptimization = false;
+ boolean foundQuotaFix = false;
+ boolean foundOtherFix = false;
+ String otherFixLine = null;
+ for (int i = startLineNumber; i < endLineNumber; i++) {
+ String line = lines[i];
+ if (line.contains(FSCK_FS_MODIFIED)) { // no need to parse above this
+ break;
+ } else if (line.startsWith("Pass ")) {
+ Matcher matcher = passPattern.matcher(line);
+ if (matcher.find()) {
+ currentPass = matcher.group(1);
+ }
+ } else if (line.startsWith("Inode ")) {
+ Matcher matcher = treeOptPattern.matcher(line);
+ if (matcher.find() && currentPass.equals("1")) {
+ foundTreeOptimization = true;
+ Slog.i(TAG, "fs_stat, partition:" + partition + " found tree optimization:"
+ + line);
+ } else {
+ foundOtherFix = true;
+ otherFixLine = line;
+ break;
+ }
+ } else if (line.startsWith("[QUOTA WARNING]") && currentPass.equals("5")) {
+ Slog.i(TAG, "fs_stat, partition:" + partition + " found quota warning:"
+ + line);
+ foundQuotaFix = true;
+ if (!foundTreeOptimization) { // only quota warning, this is real fix.
+ otherFixLine = line;
+ break;
+ }
+ } else if (line.startsWith("Update quota info") && currentPass.equals("5")) {
+ // follows "[QUOTA WARNING]", ignore
+ } else {
+ line = line.trim();
+ // ignore empty msg or any msg before Pass 1
+ if (!line.isEmpty() && !currentPass.isEmpty()) {
+ foundOtherFix = true;
+ otherFixLine = line;
+ break;
+ }
+ }
+ }
+ if (!foundOtherFix && foundTreeOptimization && foundQuotaFix) {
+ // not a real fix, so clear it.
+ Slog.i(TAG, "fs_stat, partition:" + partition +
+ " quota fix due to tree optimization");
+ stat &= ~FS_STAT_FS_FIXED;
+ } else {
+ if (otherFixLine != null) {
+ Slog.i(TAG, "fs_stat, partition:" + partition + " fix:" + otherFixLine);
+ }
+ }
+ }
+ return stat;
+ }
+
+ private static void handleFsckFsStat(Matcher match, String[] lines, int startLineNumber,
+ int endLineNumber) {
String partition = match.group(1);
int stat;
try {
@@ -412,9 +504,9 @@
Slog.w(TAG, "cannot parse fs_stat: partition:" + partition + " stat:" + match.group(2));
return;
}
-
+ stat = fixFsckFsStat(partition, stat, lines, startLineNumber, endLineNumber);
MetricsLogger.histogram(null, "boot_fs_stat_" + partition, stat);
- Slog.i(TAG, "fs_stat, partition:" + partition + " stat:" + match.group(2));
+ Slog.i(TAG, "fs_stat, partition:" + partition + " stat:0x" + Integer.toHexString(stat));
}
private static HashMap<String, Long> readTimestamps() {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 1aed501..de67c50 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -193,10 +193,10 @@
if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
/*
* It's an Error: Reraise the exception and ask the runtime to abort.
- * This will dump the pending exception as well as all thread traces
- * to the log.
*/
env->Throw(excep);
+ ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
+ env->ExceptionDescribe();
env->FatalError("java.lang.Error thrown during binder transaction.");
}
diff --git a/packages/SystemUI/res/drawable/ic_info_outline.xml b/packages/SystemUI/res/drawable/ic_info_outline.xml
new file mode 100644
index 0000000..a4a3e9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_info_outline.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 8667a5a..bb1b288 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -14,41 +14,31 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:paddingBottom="@dimen/qs_tile_padding_top"
- android:paddingTop="@dimen/qs_tile_padding_top" >
+ android:paddingTop="@dimen/qs_tile_padding_top"
+ android:paddingStart="@dimen/qs_footer_padding_start"
+ android:paddingEnd="@dimen/qs_footer_padding_end"
+ android:gravity="center_vertical"
+ android:background="?android:attr/colorPrimaryDark" >
<TextView
android:id="@+id/footer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:textSize="@dimen/qs_tile_text_size" />
+ android:gravity="start"
+ android:layout_weight="1"
+ android:textAppearance="@style/TextAppearance.QS.TileLabel"
+ android:textColor="?android:attr/textColorSecondary"/>
<ImageView
android:id="@+id/footer_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginEnd="8dp"
- android:layout_toStartOf="@id/footer_text"
+ android:layout_width="@dimen/qs_footer_icon_size"
+ android:layout_height="@dimen/qs_footer_icon_size"
android:contentDescription="@null"
- android:src="@drawable/ic_qs_vpn"
- android:visibility="invisible" />
+ android:src="@drawable/ic_info_outline" />
- <!-- Only shown if both images are visible -->
- <ImageView
- android:id="@+id/footer_icon2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginEnd="8dp"
- android:layout_toStartOf="@id/footer_icon"
- android:contentDescription="@null"
- android:src="@drawable/ic_qs_network_logging"
- android:visibility="invisible" />
-
-</RelativeLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9c7a6a0..1a3e6ce1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -263,6 +263,9 @@
<dimen name="qs_detail_item_icon_size">24dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
+ <dimen name="qs_footer_padding_start">16dp</dimen>
+ <dimen name="qs_footer_padding_end">24dp</dimen>
+ <dimen name="qs_footer_icon_size">16dp</dimen>
<!-- Desired qs icon overlay size. -->
<dimen name="qs_detail_icon_overlay_size">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 38485c7..f5e096eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -98,9 +98,6 @@
setupTileLayout();
- mFooter = new QSSecurityFooter(this, context);
- addView(mFooter.getView());
-
mPageIndicator = LayoutInflater.from(context).inflate(
R.layout.qs_page_indicator, this, false);
addView(mPageIndicator);
@@ -110,6 +107,9 @@
addDivider();
+ mFooter = new QSSecurityFooter(this, context);
+ addView(mFooter.getView());
+
updateResources();
mBrightnessController = new BrightnessController(getContext(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 5b9d95d..51c6ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2014 The Android Open Source Project
*
@@ -51,24 +50,21 @@
private final View mRootView;
private final TextView mFooterText;
private final ImageView mFooterIcon;
- private final ImageView mFooterIcon2;
private final Context mContext;
private final Callback mCallback = new Callback();
private final SecurityController mSecurityController;
private final ActivityStarter mActivityStarter;
private final Handler mMainHandler;
+ private final View mDivider;
private AlertDialog mDialog;
private QSTileHost mHost;
protected H mHandler;
private boolean mIsVisible;
- private boolean mIsIconVisible;
- private boolean mIsIcon2Visible;
private CharSequence mFooterTextContent = null;
private int mFooterTextId;
private int mFooterIconId;
- private int mFooterIcon2Id;
public QSSecurityFooter(QSPanel qsPanel, Context context) {
mRootView = LayoutInflater.from(context)
@@ -76,14 +72,13 @@
mRootView.setOnClickListener(this);
mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
- mFooterIcon2 = (ImageView) mRootView.findViewById(R.id.footer_icon2);
- mFooterIconId = R.drawable.ic_qs_vpn;
- mFooterIcon2Id = R.drawable.ic_qs_network_logging;
+ mFooterIconId = R.drawable.ic_info_outline;
mContext = context;
mMainHandler = new Handler(Looper.getMainLooper());
mActivityStarter = Dependency.get(ActivityStarter.class);
mSecurityController = Dependency.get(SecurityController.class);
mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
+ mDivider = qsPanel == null ? null : qsPanel.getDivider();
}
public void setHostEnvironment(QSTileHost host) {
@@ -130,45 +125,102 @@
}
private void handleRefreshState() {
- boolean isVpnEnabled = mSecurityController.isVpnEnabled();
- boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
- mIsIconVisible = isVpnEnabled || isNetworkLoggingEnabled;
- mIsIcon2Visible = isVpnEnabled && isNetworkLoggingEnabled;
- if (mSecurityController.isDeviceManaged()) {
- final CharSequence organizationName =
- mSecurityController.getDeviceOwnerOrganizationName();
- if (organizationName != null) {
- mFooterTextContent = mContext.getResources().getString(
- R.string.do_disclosure_with_name, organizationName);
- } else {
- mFooterTextContent =
- mContext.getResources().getString(R.string.do_disclosure_generic);
- }
- mIsVisible = true;
- int footerIconId = isVpnEnabled
- ? R.drawable.ic_qs_vpn
- : R.drawable.ic_qs_network_logging;
- if (mFooterIconId != footerIconId) {
- mFooterIconId = footerIconId;
- mMainHandler.post(mUpdateIcon);
- }
- } else {
- boolean isBranded = mSecurityController.isVpnBranded();
- mFooterTextContent = mContext.getResources().getText(
- isBranded ? R.string.branded_vpn_footer : R.string.vpn_footer);
- // Update the VPN footer icon, if needed.
- int footerIconId = isVpnEnabled
- ? (isBranded ? R.drawable.ic_qs_branded_vpn : R.drawable.ic_qs_vpn)
- : R.drawable.ic_qs_network_logging;
- if (mFooterIconId != footerIconId) {
- mFooterIconId = footerIconId;
- mMainHandler.post(mUpdateIcon);
- }
- mIsVisible = mIsIconVisible;
+ final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
+ final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
+ final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser();
+ final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile();
+ final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
+ final String vpnName = mSecurityController.getPrimaryVpnName();
+ final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
+ final CharSequence organizationName = mSecurityController.getDeviceOwnerOrganizationName();
+ final CharSequence workProfileName = mSecurityController.getWorkProfileOrganizationName();
+ // Update visibility of footer
+ mIsVisible = isDeviceManaged || hasCACerts || hasCACertsInWorkProfile ||
+ vpnName != null || vpnNameWorkProfile != null;
+ // Update the string
+ mFooterTextContent = getFooterText(isDeviceManaged, hasWorkProfile,
+ hasCACerts, hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName,
+ vpnNameWorkProfile, organizationName, workProfileName);
+ // Update the icon
+ int footerIconId = vpnName != null || vpnNameWorkProfile != null
+ ? R.drawable.ic_qs_vpn
+ : R.drawable.ic_info_outline;
+ if (mFooterIconId != footerIconId) {
+ mFooterIconId = footerIconId;
+ mMainHandler.post(mUpdateIcon);
}
mMainHandler.post(mUpdateDisplayState);
}
+ protected CharSequence getFooterText(boolean isDeviceManaged, boolean hasWorkProfile,
+ boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled,
+ String vpnName, String vpnNameWorkProfile, CharSequence organizationName,
+ CharSequence workProfileName) {
+ if (isDeviceManaged) {
+ if (hasCACerts || hasCACertsInWorkProfile || isNetworkLoggingEnabled) {
+ if (organizationName == null) {
+ return mContext.getString(
+ R.string.quick_settings_disclosure_management_monitoring);
+ }
+ return mContext.getString(
+ R.string.quick_settings_disclosure_named_management_monitoring,
+ organizationName);
+ }
+ if (vpnName != null && vpnNameWorkProfile != null) {
+ if (organizationName == null) {
+ return mContext.getString(R.string.quick_settings_disclosure_management_vpns);
+ }
+ return mContext.getString(R.string.quick_settings_disclosure_named_management_vpns,
+ organizationName);
+ }
+ if (vpnName != null || vpnNameWorkProfile != null) {
+ if (organizationName == null) {
+ return mContext.getString(
+ R.string.quick_settings_disclosure_management_named_vpn,
+ vpnName != null ? vpnName : vpnNameWorkProfile);
+ }
+ return mContext.getString(
+ R.string.quick_settings_disclosure_named_management_named_vpn,
+ organizationName,
+ vpnName != null ? vpnName : vpnNameWorkProfile);
+ }
+ if (organizationName == null) {
+ return mContext.getString(R.string.quick_settings_disclosure_management);
+ }
+ return mContext.getString(R.string.quick_settings_disclosure_named_management,
+ organizationName);
+ } // end if(isDeviceManaged)
+ if (hasCACertsInWorkProfile) {
+ if (workProfileName == null) {
+ return mContext.getString(
+ R.string.quick_settings_disclosure_managed_profile_monitoring);
+ }
+ return mContext.getString(
+ R.string.quick_settings_disclosure_named_managed_profile_monitoring,
+ workProfileName);
+ }
+ if (hasCACerts) {
+ return mContext.getString(R.string.quick_settings_disclosure_monitoring);
+ }
+ if (vpnName != null && vpnNameWorkProfile != null) {
+ return mContext.getString(R.string.quick_settings_disclosure_vpns);
+ }
+ if (vpnNameWorkProfile != null) {
+ return mContext.getString(R.string.quick_settings_disclosure_managed_profile_named_vpn,
+ vpnNameWorkProfile);
+ }
+ if (vpnName != null) {
+ if (hasWorkProfile) {
+ return mContext.getString(
+ R.string.quick_settings_disclosure_personal_profile_named_vpn,
+ vpnName);
+ }
+ return mContext.getString(R.string.quick_settings_disclosure_named_vpn,
+ vpnName);
+ }
+ return null;
+ }
+
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
@@ -182,18 +234,15 @@
final String profileOwnerPackage = mSecurityController.getProfileOwnerName();
final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
final String primaryVpn = mSecurityController.getPrimaryVpnName();
- final String profileVpn = mSecurityController.getProfileVpnName();
+ final String profileVpn = mSecurityController.getWorkProfileVpnName();
final CharSequence deviceOwnerOrganization =
mSecurityController.getDeviceOwnerOrganizationName();
boolean hasProfileOwner = mSecurityController.hasProfileOwner();
- boolean isBranded = deviceOwnerPackage == null && mSecurityController.isVpnBranded();
mDialog = new SystemUIDialog(mContext);
- if (!isBranded) {
- mDialog.setTitle(getTitle(deviceOwnerPackage));
- }
+ mDialog.setTitle(getTitle(deviceOwnerPackage));
CharSequence msg = getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn,
- profileVpn, deviceOwnerOrganization, hasProfileOwner, isBranded);
+ profileVpn, deviceOwnerOrganization, hasProfileOwner);
if (deviceOwnerPackage == null) {
mDialog.setMessage(msg);
if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
@@ -235,7 +284,7 @@
}
}
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this);
+ mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
mDialog.show();
mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@@ -244,13 +293,13 @@
return mContext.getString(R.string.status_bar_settings_settings_button);
}
- private String getPositiveButton(boolean isBranded) {
- return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done);
+ private String getPositiveButton() {
+ return mContext.getString(R.string.quick_settings_done);
}
protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage,
String primaryVpn, String profileVpn, CharSequence deviceOwnerOrganization,
- boolean hasProfileOwner, boolean isBranded) {
+ boolean hasProfileOwner) {
if (deviceOwnerPackage != null) {
final SpannableStringBuilder message = new SpannableStringBuilder();
if (deviceOwnerOrganization != null) {
@@ -273,13 +322,8 @@
return mContext.getString(R.string.monitoring_description_app_personal_work,
profileOwnerPackage, profileVpn, primaryVpn);
} else {
- if (isBranded) {
- return mContext.getString(R.string.branded_monitoring_description_app_personal,
- primaryVpn);
- } else {
- return mContext.getString(R.string.monitoring_description_app_personal,
- primaryVpn);
- }
+ return mContext.getString(R.string.monitoring_description_app_personal,
+ primaryVpn);
}
} else if (profileVpn != null) {
return mContext.getString(R.string.monitoring_description_app_work,
@@ -305,7 +349,6 @@
@Override
public void run() {
mFooterIcon.setImageResource(mFooterIconId);
- mFooterIcon2.setImageResource(mFooterIcon2Id);
}
};
@@ -316,8 +359,7 @@
mFooterText.setText(mFooterTextContent);
}
mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
- mFooterIcon.setVisibility(mIsIconVisible ? View.VISIBLE : View.INVISIBLE);
- mFooterIcon2.setVisibility(mIsIcon2Visible ? View.VISIBLE : View.INVISIBLE);
+ if (mDivider != null) mDivider.setVisibility(mIsVisible ? View.GONE : View.VISIBLE);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 3f8e41a..1fb9b69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -23,16 +23,20 @@
/** Whether the device has device owner, even if not on this user. */
boolean isDeviceManaged();
boolean hasProfileOwner();
+ boolean hasWorkProfile();
String getDeviceOwnerName();
String getProfileOwnerName();
CharSequence getDeviceOwnerOrganizationName();
+ CharSequence getWorkProfileOrganizationName();
boolean isNetworkLoggingEnabled();
boolean isVpnEnabled();
boolean isVpnRestricted();
/** Whether the VPN app should use branded VPN iconography. */
boolean isVpnBranded();
String getPrimaryVpnName();
- String getProfileVpnName();
+ String getWorkProfileVpnName();
+ boolean hasCACertInCurrentUser();
+ boolean hasCACertInWorkProfile();
void onUserSwitched(int newUserId);
public interface SecurityControllerCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 19ced23..fcb7289 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -138,6 +138,13 @@
}
@Override
+ public CharSequence getWorkProfileOrganizationName() {
+ final int profileId = getWorkProfileUserId(mCurrentUserId);
+ if (profileId == UserHandle.USER_NULL) return null;
+ return mDevicePolicyManager.getOrganizationNameForUser(profileId);
+ }
+
+ @Override
public String getPrimaryVpnName() {
VpnConfig cfg = mCurrentVpns.get(mVpnUserId);
if (cfg != null) {
@@ -147,16 +154,27 @@
}
}
+ private int getWorkProfileUserId(int userId) {
+ for (final UserInfo userInfo : mUserManager.getProfiles(userId)) {
+ if (userInfo.isManagedProfile()) {
+ return userInfo.id;
+ }
+ }
+ return UserHandle.USER_NULL;
+ }
+
@Override
- public String getProfileVpnName() {
- for (int profileId : mUserManager.getProfileIdsWithDisabled(mVpnUserId)) {
- if (profileId == mVpnUserId) {
- continue;
- }
- VpnConfig cfg = mCurrentVpns.get(profileId);
- if (cfg != null) {
- return getNameForVpnConfig(cfg, UserHandle.of(profileId));
- }
+ public boolean hasWorkProfile() {
+ return getWorkProfileUserId(mCurrentUserId) != UserHandle.USER_NULL;
+ }
+
+ @Override
+ public String getWorkProfileVpnName() {
+ final int profileId = getWorkProfileUserId(mVpnUserId);
+ if (profileId == UserHandle.USER_NULL) return null;
+ VpnConfig cfg = mCurrentVpns.get(profileId);
+ if (cfg != null) {
+ return getNameForVpnConfig(cfg, UserHandle.of(profileId));
}
return null;
}
@@ -199,6 +217,18 @@
}
@Override
+ public boolean hasCACertInCurrentUser() {
+ //TODO: implement
+ return false;
+ }
+
+ @Override
+ public boolean hasCACertInWorkProfile() {
+ //TODO: implement
+ return false;
+ }
+
+ @Override
public void removeCallback(SecurityControllerCallback callback) {
synchronized (mCallbacks) {
if (callback == null) return;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 697cac9..b8b046b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -433,7 +433,7 @@
return false;
}
});
- row.icon = (ImageButton) row.view.findViewById(R.id.volume_row_icon);
+ row.icon = row.view.findViewById(R.id.volume_row_icon);
row.icon.setImageResource(iconRes);
if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
row.icon.setOnClickListener(new OnClickListener() {
@@ -465,6 +465,8 @@
row.userAttempt = 0; // reset the grace period, slider updates immediately
}
});
+ } else {
+ row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 1ff373c..ff644d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -40,6 +40,15 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+/*
+ * Compile and run the whole SystemUI test suite:
+ runtest --path frameworks/base/packages/SystemUI/tests
+ *
+ * Compile and run just this class:
+ runtest --path \
+ frameworks/base/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+*/
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class QSSecurityFooterTest extends SysuiTestCase {
@@ -47,11 +56,11 @@
private final String MANAGING_ORGANIZATION = "organization";
private final String DEVICE_OWNER_PACKAGE = "TestDPC";
private final String VPN_PACKAGE = "TestVPN";
+ private final String VPN_PACKAGE_2 = "TestVPN 2";
private ViewGroup mRootView;
private TextView mFooterText;
private TestableImageView mFooterIcon;
- private TestableImageView mFooterIcon2;
private QSSecurityFooter mFooter;
private SecurityController mSecurityController = mock(SecurityController.class);
@@ -69,15 +78,12 @@
mRootView = (ViewGroup) mFooter.getView();
mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
mFooterIcon = (TestableImageView) mRootView.findViewById(R.id.footer_icon);
- mFooterIcon2 = (TestableImageView) mRootView.findViewById(R.id.footer_icon2);
mFooter.setHostEnvironment(null);
}
@Test
public void testUnmanaged() {
when(mSecurityController.isDeviceManaged()).thenReturn(false);
- when(mSecurityController.isVpnEnabled()).thenReturn(false);
- when(mSecurityController.isVpnBranded()).thenReturn(false);
mFooter.refreshState();
waitForIdleSync(mFooter.mHandler);
@@ -91,8 +97,12 @@
mFooter.refreshState();
waitForIdleSync(mFooter.mHandler);
- assertEquals(mContext.getString(R.string.do_disclosure_generic), mFooterText.getText());
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management),
+ mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
+ assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ // -1 == never set.
+ assertEquals(-1, mFooterIcon.getLastImageResource());
}
@Test
@@ -103,37 +113,100 @@
mFooter.refreshState();
waitForIdleSync(mFooter.mHandler);
- assertEquals(mContext.getString(R.string.do_disclosure_with_name, MANAGING_ORGANIZATION),
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_management,
+ MANAGING_ORGANIZATION),
mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
+ assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ // -1 == never set.
+ assertEquals(-1, mFooterIcon.getLastImageResource());
}
@Test
public void testNetworkLoggingEnabled() {
when(mSecurityController.isDeviceManaged()).thenReturn(true);
when(mSecurityController.isNetworkLoggingEnabled()).thenReturn(true);
- when(mSecurityController.isVpnEnabled()).thenReturn(false);
mFooter.refreshState();
waitForIdleSync(mFooter.mHandler);
- assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(R.drawable.ic_qs_network_logging, mFooterIcon.getLastImageResource());
- assertEquals(View.INVISIBLE, mFooterIcon2.getVisibility());
- }
-
- @Test
- public void testVpnEnabled() {
- when(mSecurityController.isDeviceManaged()).thenReturn(true);
- when(mSecurityController.isNetworkLoggingEnabled()).thenReturn(false);
- when(mSecurityController.isVpnEnabled()).thenReturn(true);
- when(mSecurityController.isVpnBranded()).thenReturn(false);
- mFooter.refreshState();
-
- waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
+ mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
// -1 == never set.
assertEquals(-1, mFooterIcon.getLastImageResource());
- assertEquals(View.INVISIBLE, mFooterIcon2.getVisibility());
+
+ // Same situation, but with organization name set
+ when(mSecurityController.getDeviceOwnerOrganizationName())
+ .thenReturn(MANAGING_ORGANIZATION);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_named_management_monitoring,
+ MANAGING_ORGANIZATION),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testManagedCACertsInstalled() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.hasCACertInCurrentUser()).thenReturn(true);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testManagedOneVpnEnabled() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.isVpnEnabled()).thenReturn(true);
+ when(mSecurityController.getPrimaryVpnName()).thenReturn(VPN_PACKAGE);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_named_vpn,
+ VPN_PACKAGE),
+ mFooterText.getText());
+ assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+
+ // Same situation, but with organization name set
+ when(mSecurityController.getDeviceOwnerOrganizationName())
+ .thenReturn(MANAGING_ORGANIZATION);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_named_management_named_vpn,
+ MANAGING_ORGANIZATION, VPN_PACKAGE),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testManagedTwoVpnsEnabled() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(true);
+ when(mSecurityController.isVpnEnabled()).thenReturn(true);
+ when(mSecurityController.getPrimaryVpnName()).thenReturn(VPN_PACKAGE);
+ when(mSecurityController.getWorkProfileVpnName()).thenReturn(VPN_PACKAGE_2);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
+ mFooterText.getText());
+ assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+
+ // Same situation, but with organization name set
+ when(mSecurityController.getDeviceOwnerOrganizationName())
+ .thenReturn(MANAGING_ORGANIZATION);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_management_vpns,
+ MANAGING_ORGANIZATION),
+ mFooterText.getText());
}
@Test
@@ -141,15 +214,101 @@
when(mSecurityController.isDeviceManaged()).thenReturn(true);
when(mSecurityController.isNetworkLoggingEnabled()).thenReturn(true);
when(mSecurityController.isVpnEnabled()).thenReturn(true);
- when(mSecurityController.isVpnBranded()).thenReturn(false);
+ when(mSecurityController.getPrimaryVpnName()).thenReturn("VPN Test App");
mFooter.refreshState();
waitForIdleSync(mFooter.mHandler);
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
- assertEquals(View.VISIBLE, mFooterIcon2.getVisibility());
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testWorkProfileCACertsInstalled() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(false);
+ when(mSecurityController.hasCACertInWorkProfile()).thenReturn(true);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
// -1 == never set.
assertEquals(-1, mFooterIcon.getLastImageResource());
- assertEquals(-1, mFooterIcon2.getLastImageResource());
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_managed_profile_monitoring),
+ mFooterText.getText());
+
+ // Same situation, but with organization name set
+ when(mSecurityController.getWorkProfileOrganizationName())
+ .thenReturn(MANAGING_ORGANIZATION);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_named_managed_profile_monitoring,
+ MANAGING_ORGANIZATION),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testCACertsInstalled() {
+ when(mSecurityController.isDeviceManaged()).thenReturn(false);
+ when(mSecurityController.hasCACertInCurrentUser()).thenReturn(true);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ // -1 == never set.
+ assertEquals(-1, mFooterIcon.getLastImageResource());
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_monitoring),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testTwoVpnsEnabled() {
+ when(mSecurityController.isVpnEnabled()).thenReturn(true);
+ when(mSecurityController.getPrimaryVpnName()).thenReturn(VPN_PACKAGE);
+ when(mSecurityController.getWorkProfileVpnName()).thenReturn(VPN_PACKAGE_2);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_vpns),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testWorkProfileVpnEnabled() {
+ when(mSecurityController.isVpnEnabled()).thenReturn(true);
+ when(mSecurityController.getWorkProfileVpnName()).thenReturn(VPN_PACKAGE_2);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_managed_profile_named_vpn,
+ VPN_PACKAGE_2),
+ mFooterText.getText());
+ }
+
+ @Test
+ public void testVpnEnabled() {
+ when(mSecurityController.isVpnEnabled()).thenReturn(true);
+ when(mSecurityController.getPrimaryVpnName()).thenReturn(VPN_PACKAGE);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(R.drawable.ic_qs_vpn, mFooterIcon.getLastImageResource());
+ assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_vpn,
+ VPN_PACKAGE),
+ mFooterText.getText());
+
+ when(mSecurityController.hasWorkProfile()).thenReturn(true);
+ mFooter.refreshState();
+
+ waitForIdleSync(mFooter.mHandler);
+ assertEquals(mContext.getString(
+ R.string.quick_settings_disclosure_personal_profile_named_vpn,
+ VPN_PACKAGE),
+ mFooterText.getText());
}
@Test
@@ -160,8 +319,7 @@
null /* primaryVpn */,
null /* profileVpn */,
null /* deviceOwnerOrganization */,
- false /* hasProfileOwner */,
- false /* isBranded */));
+ false /* hasProfileOwner */));
}
@Test
@@ -172,8 +330,7 @@
VPN_PACKAGE,
null /* profileVpn */,
null /* deviceOwnerOrganization */,
- false /* hasProfileOwner */,
- false /* isBranded */));
+ false /* hasProfileOwner */));
}
@Test
@@ -184,8 +341,7 @@
null /* primaryVpn */,
null /* profileVpn */,
MANAGING_ORGANIZATION,
- false /* hasProfileOwner */,
- false /* isBranded */));
+ false /* hasProfileOwner */));
}
@Test
@@ -196,8 +352,7 @@
VPN_PACKAGE,
null /* profileVpn */,
MANAGING_ORGANIZATION,
- false /* hasProfileOwner */,
- false /* isBranded */));
+ false /* hasProfileOwner */));
}
private CharSequence getExpectedMessage(boolean hasDeviceOwnerOrganization, boolean hasVPN) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java
index 157b8a0..fee5e32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeSecurityController.java
@@ -36,6 +36,11 @@
}
@Override
+ public boolean hasWorkProfile() {
+ return false;
+ }
+
+ @Override
public String getDeviceOwnerName() {
return null;
}
@@ -51,6 +56,11 @@
}
@Override
+ public CharSequence getWorkProfileOrganizationName() {
+ return null;
+ }
+
+ @Override
public boolean isNetworkLoggingEnabled() {
return false;
}
@@ -76,11 +86,21 @@
}
@Override
- public String getProfileVpnName() {
+ public String getWorkProfileVpnName() {
return null;
}
@Override
+ public boolean hasCACertInCurrentUser() {
+ return false;
+ }
+
+ @Override
+ public boolean hasCACertInWorkProfile() {
+ return false;
+ }
+
+ @Override
public void onUserSwitched(int newUserId) {
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 90e9b92..3cb2f35 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -356,7 +356,6 @@
private void rebuildRestoredPackages() {
mRestoredPackages.clear();
- mSnoozingForCurrentProfiles.clear();
String secureSettingName = restoredSettingName(mConfig.secureSettingName);
String secondarySettingName = mConfig.secondarySettingName == null
? null : restoredSettingName(mConfig.secondarySettingName);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8a6a940..e13aeaf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3611,7 +3611,7 @@
final boolean aboveThreshold =
record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
- if (DBG || record.isIntercepted())
+ if (DBG)
Slog.v(TAG,
"pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
" intercept=" + record.isIntercepted()
diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverFixFsckFsStatTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverFixFsckFsStatTest.java
new file mode 100644
index 0000000..362c47a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BootReceiverFixFsckFsStatTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 com.android.server;
+
+import static junit.framework.Assert.*;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BootReceiverFixFsckFsStatTest {
+
+ private static final String PARTITION = "userdata";
+
+ @Test
+ public void testTreeOptimization() {
+ final String[] logs = {
+ "e2fsck 1.43.3 (04-Sep-2016)",
+ "Pass 1: Checking inodes, blocks, and sizes",
+ "Inode 877141 extent tree (at level 1) could be shorter. Fix? yes",
+ " ",
+ "Pass 1E: Optimizing extent trees",
+ "Pass 2: Checking directory structure",
+ "Pass 3: Checking directory connectivity",
+ "Pass 4: Checking reference counts",
+ "Pass 5: Checking group summary information",
+ "[QUOTA WARNING] Usage inconsistent for ID 10038:actual (71667712, 1000) != expected (71671808, 1000)",
+ "Update quota info for quota type 0? yes",
+ " ",
+ "[QUOTA WARNING] Usage inconsistent for ID 10038:actual (59555840, 953) != expected (59559936, 953)",
+ "Update quota info for quota type 1? yes",
+ " ",
+ "/dev/block/platform/soc/624000.ufshc/by-name/userdata: ***** FILE SYSTEM WAS MODIFIED *****"
+ };
+ doTestFsckFsStat(logs, 0x405, 5, 0, logs.length);
+
+ final String[] doubleLogs = new String[logs.length * 2];
+ System.arraycopy(logs, 0, doubleLogs, 0, logs.length);
+ System.arraycopy(logs, 0, doubleLogs, logs.length, logs.length);
+ doTestFsckFsStat(doubleLogs, 0x401, 1, 0, logs.length);
+ doTestFsckFsStat(doubleLogs, 0x402, 2, logs.length, logs.length * 2);
+ }
+
+ @Test
+ public void testQuotaOnly() {
+ final String[] logs = {
+ "e2fsck 1.43.3 (04-Sep-2016)",
+ "Pass 1: Checking inodes, blocks, and sizes",
+ "Pass 1E: Optimizing extent trees",
+ "Pass 2: Checking directory structure",
+ "Pass 3: Checking directory connectivity",
+ "Pass 4: Checking reference counts",
+ "Pass 5: Checking group summary information",
+ "[QUOTA WARNING] Usage inconsistent for ID 10038:actual (71667712, 1000) != expected (71671808, 1000)",
+ "Update quota info for quota type 0? yes",
+ " ",
+ "[QUOTA WARNING] Usage inconsistent for ID 10038:actual (59555840, 953) != expected (59559936, 953)",
+ "Update quota info for quota type 1? yes",
+ " ",
+ "/dev/block/platform/soc/624000.ufshc/by-name/userdata: ***** FILE SYSTEM WAS MODIFIED *****"
+ };
+ doTestFsckFsStat(logs, 0x405, 0x405, 0, logs.length);
+ }
+
+ @Test
+ public void testOrphaned() {
+ final String[] logs = {
+ "e2fsck 1.43.3 (04-Sep-2016)",
+ "Pass 1: Checking inodes, blocks, and sizes",
+ "Inodes that were part of a corrupted orphan linked list found. Fix? yes",
+ " ",
+ "Inode 589877 was part of the orphaned inode list. FIXED.",
+ " ",
+ "Inode 589878 was part of the orphaned inode list. FIXED.",
+ " ",
+ "Pass 2: Checking directory structure",
+ "Pass 3: Checking directory connectivity",
+ "Pass 4: Checking reference counts",
+ "Pass 5: Checking group summary information",
+ " ",
+ "/dev/block/platform/soc/624000.ufshc/by-name/userdata: ***** FILE SYSTEM WAS MODIFIED *****"
+ };
+ doTestFsckFsStat(logs, 0x405, 0x405, 0, logs.length);
+ }
+
+ private void doTestFsckFsStat(String[] lines, int statOrg, int statUpdated, int startLineNumber,
+ int endLineNumber) {
+ assertEquals(statUpdated, BootReceiver.fixFsckFsStat(PARTITION, statOrg, lines,
+ startLineNumber, endLineNumber));
+ }
+}