Merge "Respect empty vibration effect configs in PhoneWindowManager and VibratorService" into oc-dev
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index dca7ea6..3689d5e 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -16,12 +16,16 @@
#define LOG_TAG "BootAnimation"
+#include <stdint.h>
+#include <inttypes.h>
+
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <sys/resource.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <utils/threads.h>
#include "BootAnimation.h"
@@ -47,6 +51,26 @@
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
+ // TODO: replace this with better waiting logic in future, b/35253872
+ int64_t waitStartTime = elapsedRealtime();
+ sp<IServiceManager> sm = defaultServiceManager();
+ const String16 name("SurfaceFlinger");
+ const int SERVICE_WAIT_SLEEP_MS = 100;
+ const int LOG_PER_RETRIES = 10;
+ int retry = 0;
+ while (sm->checkService(name) == nullptr) {
+ retry++;
+ if ((retry % LOG_PER_RETRIES) == 0) {
+ ALOGW("Waiting for SurfaceFlinger, waited for %" PRId64 " ms",
+ elapsedRealtime() - waitStartTime);
+ }
+ usleep(SERVICE_WAIT_SLEEP_MS * 1000);
+ };
+ int64_t totalWaited = elapsedRealtime() - waitStartTime;
+ if (totalWaited > SERVICE_WAIT_SLEEP_MS) {
+ ALOGI("Waiting for SurfaceFlinger took %" PRId64 " ms", totalWaited);
+ }
+
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 95d55dc..3e26e0f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2603,23 +2603,25 @@
f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
}
- boolean addedChild = false;
+ FragmentManagerNonConfig child;
if (f.mChildFragmentManager != null) {
f.mChildFragmentManager.saveNonConfig();
- FragmentManagerNonConfig child = f.mChildFragmentManager.mSavedNonConfig;
- if (child != null) {
- if (childFragments == null) {
- childFragments = new ArrayList<>();
- for (int j = 0; j < i; j++) {
- childFragments.add(null);
- }
- }
- childFragments.add(child);
- addedChild = true;
+ child = f.mChildFragmentManager.mSavedNonConfig;
+ } else {
+ // f.mChildNonConfig may be not null, when the parent fragment is
+ // in the backstack.
+ child = f.mChildNonConfig;
+ }
+
+ if (childFragments == null && child != null) {
+ childFragments = new ArrayList<>(mActive.size());
+ for (int j = 0; j < i; j++) {
+ childFragments.add(null);
}
}
- if (childFragments != null && !addedChild) {
- childFragments.add(null);
+
+ if (childFragments != null) {
+ childFragments.add(child);
}
}
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 87e6a84..4cee2df 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -343,5 +343,5 @@
public abstract int getUidTargetSdkVersion(int uid);
/** Whether the binder caller can access instant apps. */
- public abstract boolean canAccessInstantApps(int callingUid);
+ public abstract boolean canAccessInstantApps(int callingUid, int userId);
}
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index e6e448e..c9eecf1 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -88,7 +88,7 @@
}
@SuppressWarnings("deprecation")
- public static class DeviceCaptureCallbackProxy extends CameraDeviceImpl.CaptureCallback {
+ public static class DeviceCaptureCallbackProxy implements CameraDeviceImpl.CaptureCallback {
private final MethodNameInvoker<CameraDeviceImpl.CaptureCallback> mProxy;
public DeviceCaptureCallbackProxy(
@@ -138,6 +138,13 @@
int sequenceId) {
mProxy.invoke("onCaptureSequenceAborted", camera, sequenceId);
}
+
+ @Override
+ public void onCaptureBufferLost(CameraDevice camera,
+ CaptureRequest request, Surface target, long frameNumber) {
+ mProxy.invoke("onCaptureBufferLost", camera, request, target, frameNumber);
+ }
+
}
public static class SessionStateCallbackProxy
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 16ffee0..b3938cb 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -452,6 +452,37 @@
private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy(
Handler handler, CaptureCallback callback) {
CameraDeviceImpl.CaptureCallback localCallback = new CameraDeviceImpl.CaptureCallback() {
+
+ @Override
+ public void onCaptureStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp, long frameNumber) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCapturePartial(CameraDevice camera,
+ CaptureRequest request, android.hardware.camera2.CaptureResult result) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCaptureProgressed(CameraDevice camera,
+ CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCaptureCompleted(CameraDevice camera,
+ CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCaptureFailed(CameraDevice camera,
+ CaptureRequest request, android.hardware.camera2.CaptureFailure failure) {
+ // Do nothing
+ }
+
@Override
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
@@ -463,6 +494,13 @@
int sequenceId) {
finishPendingSequence(sequenceId);
}
+
+ @Override
+ public void onCaptureBufferLost(CameraDevice camera,
+ CaptureRequest request, Surface target, long frameNumber) {
+ // Do nothing
+ }
+
};
/*
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ab87f15..0d5c5e3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1112,8 +1112,11 @@
* <p>A callback for tracking the progress of a {@link CaptureRequest}
* submitted to the camera device.</p>
*
+ * An interface instead of an abstract class because this is internal and
+ * we want to make sure we always implement all its callbacks until we reach
+ * the public layer.
*/
- public static abstract class CaptureCallback {
+ public interface CaptureCallback {
/**
* This constant is used to indicate that no images were captured for
@@ -1130,9 +1133,7 @@
* @see android.media.MediaActionSound
*/
public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp, long frameNumber) {
- // default empty implementation
- }
+ CaptureRequest request, long timestamp, long frameNumber);
/**
* This method is called when some results from an image capture are
@@ -1141,9 +1142,7 @@
* @hide
*/
public void onCapturePartial(CameraDevice camera,
- CaptureRequest request, CaptureResult result) {
- // default empty implementation
- }
+ CaptureRequest request, CaptureResult result);
/**
* This method is called when an image capture makes partial forward progress; some
@@ -1151,18 +1150,14 @@
*
*/
public void onCaptureProgressed(CameraDevice camera,
- CaptureRequest request, CaptureResult partialResult) {
- // default empty implementation
- }
+ CaptureRequest request, CaptureResult partialResult);
/**
* This method is called when an image capture has fully completed and all the
* result metadata is available.
*/
public void onCaptureCompleted(CameraDevice camera,
- CaptureRequest request, TotalCaptureResult result) {
- // default empty implementation
- }
+ CaptureRequest request, TotalCaptureResult result);
/**
* This method is called instead of {@link #onCaptureCompleted} when the
@@ -1170,9 +1165,7 @@
* request.
*/
public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request, CaptureFailure failure) {
- // default empty implementation
- }
+ CaptureRequest request, CaptureFailure failure);
/**
* This method is called independently of the others in CaptureCallback,
@@ -1180,9 +1173,7 @@
* or {@link CaptureFailure} for it have been returned via this callback.
*/
public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, long frameNumber) {
- // default empty implementation
- }
+ int sequenceId, long frameNumber);
/**
* This method is called independently of the others in CaptureCallback,
@@ -1190,14 +1181,16 @@
* or {@link CaptureFailure} for it have been returned via this callback.
*/
public void onCaptureSequenceAborted(CameraDevice camera,
- int sequenceId) {
- // default empty implementation
- }
+ int sequenceId);
+ /**
+ * This method is called independently of the others in CaptureCallback, if an output buffer
+ * is dropped for a particular capture request.
+ *
+ * Loss of metadata is communicated via onCaptureFailed, independently of any buffer loss.
+ */
public void onCaptureBufferLost(CameraDevice camera,
- CaptureRequest request, Surface target, long frameNumber) {
- // default empty implementation
- }
+ CaptureRequest request, Surface target, long frameNumber);
}
/**
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b00e65a..324a08c 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -932,7 +932,6 @@
} else if (mAuthenticationCallback != null) {
mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
getErrorString(errMsgId, vendorCode));
- mAuthenticationCallback = null;
} else if (mRemovalCallback != null) {
mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
getErrorString(errMsgId, vendorCode));
@@ -953,7 +952,6 @@
final AuthenticationResult result =
new AuthenticationResult(mCryptoObject, fp, userId);
mAuthenticationCallback.onAuthenticationSucceeded(result);
- mAuthenticationCallback = null;
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 4bad7ab..a2fb9db 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -807,8 +807,20 @@
}
/**
- * Verifies the the current flash of the device is consistent with what
+ * True if Treble is enabled and required for this device.
+ *
+ * @hide
+ */
+ public static final boolean IS_TREBLE_ENABLED =
+ SystemProperties.getBoolean("ro.treble.enabled", false);
+
+ /**
+ * Verifies the current flash of the device is consistent with what
* was expected at build time.
+ *
+ * Treble devices will verify the Vendor Interface (VINTF). A device
+ * launched without Treble:
+ *
* 1) Checks that device fingerprint is defined and that it matches across
* various partitions.
* 2) Verifies radio and bootloader partitions are those expected in the build.
@@ -819,6 +831,17 @@
// Don't care on eng builds. Incremental build may trigger false negative.
if (IS_ENG) return true;
+ if (IS_TREBLE_ENABLED) {
+ int result = VintfObject.verify(new String[0]);
+
+ if (result != 0) {
+ Slog.e(TAG, "Vendor interface is incompatible, error="
+ + String.valueOf(result));
+ }
+
+ return result == 0;
+ }
+
final String system = SystemProperties.get("ro.build.fingerprint");
final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 447f280..d2598c7 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -22,9 +22,12 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
import libcore.io.Streams;
@@ -570,7 +573,16 @@
// Having set up the BCB (bootloader control block), go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
+ String reason = PowerManager.REBOOT_RECOVERY_UPDATE;
+
+ // On TV, reboot quiescently if the screen is off
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ if (wm.getDefaultDisplay().getState() != Display.STATE_ON) {
+ reason += ",quiescent";
+ }
+ }
+ pm.reboot(reason);
throw new IOException("Reboot failed (no permissions?)");
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index ca1bf58..636519b 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -112,6 +112,7 @@
// Set up and attach container.
mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator, false);
+ mContainer.setSaveFromParentEnabled(false);
mDelegator.addView(mContainer);
// Set up header views.
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index fc2d1fa..4f9316f 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -115,7 +115,8 @@
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(layoutResourceId, mDelegator, true);
+ final View view = inflater.inflate(layoutResourceId, mDelegator, true);
+ view.setSaveFromParentEnabled(false);
OnValueChangeListener onChangeListener = new OnValueChangeListener() {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 05d0f96..d3c83ee 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -137,6 +137,7 @@
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_material);
final View mainView = inflater.inflate(layoutResourceId, delegator);
+ mainView.setSaveFromParentEnabled(false);
mRadialTimePickerHeader = mainView.findViewById(R.id.time_header);
mRadialTimePickerHeader.setOnTouchListener(new NearestTouchDelegate());
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 813c30e3..7a7d9a9 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -83,7 +83,8 @@
a.recycle();
final LayoutInflater inflater = LayoutInflater.from(mContext);
- inflater.inflate(layoutResourceId, mDelegator, true);
+ final View view = inflater.inflate(layoutResourceId, mDelegator, true);
+ view.setSaveFromParentEnabled(false);
// hour
mHourSpinner = delegator.findViewById(R.id.hour);
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a9bec41..2013ac0 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -762,14 +762,6 @@
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
String property = "wrap." + args.niceName;
- if (property.length() > 31) {
- // Properties with a trailing "." are illegal.
- if (property.charAt(30) != '.') {
- property = property.substring(0, 31);
- } else {
- property = property.substring(0, 30);
- }
- }
args.invokeWith = SystemProperties.get(property);
if (args.invokeWith != null && args.invokeWith.length() == 0) {
args.invokeWith = null;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 18cfc99..8ed76de 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3317,12 +3317,16 @@
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
-
- <!-- Allows the holder to access the instant applications on the device.
+ <!-- Allows the holder to access and manage instant applications on the device.
@hide -->
<permission android:name="android.permission.ACCESS_INSTANT_APPS"
android:protectionLevel="signature|installer|verifier" />
+ <!-- Allows the holder to view the instant applications on the device.
+ @hide -->
+ <permission android:name="android.permission.VIEW_INSTANT_APPS"
+ android:protectionLevel="signature|preinstalled" />
+
<!-- Allows receiving the usage of media resource e.g. video/audio codec and
graphic memory.
@hide -->
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index ebab129..5a7bca4 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -50,14 +50,11 @@
import android.content.ClipData;
import android.content.ClipboardManager;
-import android.text.TextUtils;
-import android.text.Spanned;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
@@ -72,8 +69,6 @@
import com.android.frameworks.coretests.R;
-import junit.framework.AssertionFailedError;
-
/**
* Tests the TextView widget from an Activity
*/
@@ -694,6 +689,51 @@
assertFalse(textView.hasTransientState());
}
+ public void testResetMenuItemTitle() throws Exception {
+ getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null);
+ final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
+ final int itemId = 1;
+ final String title1 = " AFIGBO";
+ final int index = title1.indexOf('I');
+ final String title2 = title1.substring(index);
+ final String[] title = new String[]{title1};
+ textView.post(() -> textView.setCustomSelectionActionModeCallback(
+ new ActionMode.Callback() {
+ @Override
+ public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
+ menu.removeItem(itemId);
+ menu.add(Menu.NONE /* group */, itemId, 0 /* order */, title[0]);
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
+ return false;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode actionMode) {
+ }
+ }));
+ onView(withId(R.id.textview)).perform(replaceText(title1));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(index));
+ sleepForFloatingToolbarPopup();
+ assertFloatingToolbarContainsItem(title1);
+
+ // Change the menu item title.
+ title[0] = title2;
+ // Change the selection to invalidate the action mode without restarting it.
+ onHandleView(com.android.internal.R.id.selection_start_handle)
+ .perform(dragHandle(textView, Handle.SELECTION_START, index));
+ sleepForFloatingToolbarPopup();
+ assertFloatingToolbarContainsItem(title2);
+ }
+
public void testAssistItemIsAtIndexZero() throws Exception {
getActivity().getSystemService(TextClassificationManager.class).setTextClassifier(null);
final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 13016ff..0209cea 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -90,7 +90,8 @@
/**
* Set the shader's local matrix. Passing null will reset the shader's
- * matrix to identity.
+ * matrix to identity. If the matrix has scale value as 0, the drawing
+ * result is undefined.
*
* @param localM The shader's new local matrix, or null to specify identity
*/
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index bfd0604..8f314c9 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -58,11 +58,11 @@
* mask using {@code setId(..., android.R.id.mask)} or an existing mask layer
* may be replaced using {@code setDrawableByLayerId(android.R.id.mask, ...)}.
* <pre>
- * <code><!-- A red ripple masked against an opaque rectangle. --/>
- * <ripple android:color="#ffff0000">
- * <item android:id="@android:id/mask"
+ * <code><!-- A red ripple masked against an opaque rectangle. --/>
+ * <ripple android:color="#ffff0000">
+ * <item android:id="@android:id/mask"
* android:drawable="@android:color/white" />
- * </ripple></code>
+ * </ripple></code>
* </pre>
* <p>
* If a mask layer is set, the ripple effect will be masked against that layer
@@ -71,15 +71,15 @@
* If no mask layer is set, the ripple effect is masked against the composite
* of the child layers.
* <pre>
- * <code><!-- A green ripple drawn atop a black rectangle. --/>
- * <ripple android:color="#ff00ff00">
- * <item android:drawable="@android:color/black" />
- * </ripple>
+ * <code><!-- A green ripple drawn atop a black rectangle. --/>
+ * <ripple android:color="#ff00ff00">
+ * <item android:drawable="@android:color/black" />
+ * </ripple>
*
- * <!-- A blue ripple drawn atop a drawable resource. --/>
- * <ripple android:color="#ff0000ff">
- * <item android:drawable="@drawable/my_drawable" />
- * </ripple></code>
+ * <!-- A blue ripple drawn atop a drawable resource. --/>
+ * <ripple android:color="#ff0000ff">
+ * <item android:drawable="@drawable/my_drawable" />
+ * </ripple></code>
* </pre>
* <p>
* If no child layers or mask is specified and the ripple is set as a View
@@ -87,8 +87,8 @@
* background within the View's hierarchy. In this case, the drawing region
* may extend outside of the Drawable bounds.
* <pre>
- * <code><!-- An unbounded red ripple. --/>
- * <ripple android:color="#ffff0000" /></code>
+ * <code><!-- An unbounded red ripple. --/>
+ * <ripple android:color="#ffff0000" /></code>
* </pre>
*
* @attr ref android.R.styleable#RippleDrawable_color
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 05625c7..1ddbcad 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -52,6 +52,7 @@
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.annotation.MainThread;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Notification;
@@ -126,6 +127,8 @@
* <li>Stops itself if it doesn't have any process left to monitor.
* </ol>
* </ol>
+ *
+ * TODO: There are multiple threads involved. Add synchronization accordingly.
*/
public class BugreportProgressService extends Service {
private static final String TAG = "BugreportProgressService";
@@ -201,11 +204,15 @@
private static final String NOTIFICATION_CHANNEL_ID = "bugreports";
+ private final Object mLock = new Object();
+
/** Managed dumpstate processes (keyed by id) */
private final SparseArray<DumpstateListener> mProcesses = new SparseArray<>();
private Context mContext;
- private ServiceHandler mMainHandler;
+
+ private Handler mMainThreadHandler;
+ private ServiceHandler mServiceHandler;
private ScreenshotHandler mScreenshotHandler;
private final BugreportInfoDialog mInfoDialog = new BugreportInfoDialog();
@@ -234,7 +241,8 @@
@Override
public void onCreate() {
mContext = getApplicationContext();
- mMainHandler = new ServiceHandler("BugreportProgressServiceMainThread");
+ mMainThreadHandler = new Handler(Looper.getMainLooper());
+ mServiceHandler = new ServiceHandler("BugreportProgressServiceMainThread");
mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread");
mScreenshotsDir = new File(getFilesDir(), SCREENSHOT_DIR);
@@ -260,10 +268,10 @@
Log.v(TAG, "onStartCommand(): " + dumpIntent(intent));
if (intent != null) {
// Handle it in a separate thread.
- final Message msg = mMainHandler.obtainMessage();
+ final Message msg = mServiceHandler.obtainMessage();
msg.what = MSG_SERVICE_COMMAND;
msg.obj = intent;
- mMainHandler.sendMessage(msg);
+ mServiceHandler.sendMessage(msg);
}
// If service is killed it cannot be recreated because it would not know which
@@ -278,7 +286,7 @@
@Override
public void onDestroy() {
- mMainHandler.getLooper().quit();
+ mServiceHandler.getLooper().quit();
mScreenshotHandler.getLooper().quit();
super.onDestroy();
}
@@ -613,7 +621,7 @@
// ignore it
}
- mInfoDialog.initialize(mContext, info);
+ mMainThreadHandler.post(() -> mInfoDialog.initialize(mContext, info));
}
/**
@@ -652,11 +660,11 @@
private void takeScreenshot(int id, int delay) {
if (delay > 0) {
Log.d(TAG, "Taking screenshot for " + id + " in " + delay + " seconds");
- final Message msg = mMainHandler.obtainMessage();
+ final Message msg = mServiceHandler.obtainMessage();
msg.what = MSG_DELAYED_SCREENSHOT;
msg.arg1 = id;
msg.arg2 = delay - 1;
- mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
+ mServiceHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
return;
}
@@ -696,7 +704,7 @@
boolean taken = takeScreenshot(mContext, screenshotFile);
setTakingScreenshot(false);
- Message.obtain(mMainHandler, MSG_SCREENSHOT_RESPONSE, requestMsg.arg1, taken ? 1 : 0,
+ Message.obtain(mServiceHandler, MSG_SCREENSHOT_RESPONSE, requestMsg.arg1, taken ? 1 : 0,
screenshotFile).sendToTarget();
}
@@ -1111,6 +1119,12 @@
* description will be saved on {@code description.txt}.
*/
private void addDetailsToZipFile(BugreportInfo info) {
+ synchronized (mLock) {
+ addDetailsToZipFileLocked(info);
+ }
+ }
+
+ private void addDetailsToZipFileLocked(BugreportInfo info) {
if (info.bugreportFile == null) {
// One possible reason is a bug in the Parcelization code.
Log.wtf(TAG, "addDetailsToZipFile(): no bugreportFile on " + info);
@@ -1432,6 +1446,7 @@
/**
* Sets its internal state and displays the dialog.
*/
+ @MainThread
void initialize(final Context context, BugreportInfo info) {
final String dialogTitle =
context.getString(R.string.bugreport_info_dialog_title, info.id);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 823b9b1..8bfcc74 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -355,7 +355,7 @@
assertProgressNotification(NEW_NAME, 00.00f);
Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
- mScreenshotPath);
+ mScreenshotPath, TITLE);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS);
@@ -410,7 +410,7 @@
assertProgressNotification(NEW_NAME, 00.00f);
Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
- plainText? mPlainTextPath : mZipPath, mScreenshotPath);
+ plainText? mPlainTextPath : mZipPath, mScreenshotPath, TITLE);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
NEW_NAME, TITLE, mDescription, 0, RENAMED_SCREENSHOTS);
@@ -465,7 +465,7 @@
sendBugreportStarted(ID2, PID2, NAME2, 1000);
sendBugreportFinished(ID, mZipPath, mScreenshotPath);
- Bundle extras = acceptBugreportAndGetSharedIntent(ID);
+ Bundle extras = acceptBugreportAndGetSharedIntent(TITLE);
detailsUi = new DetailsUi(mUiBot, ID2, NAME2);
detailsUi.assertName(NAME2);
@@ -479,7 +479,7 @@
// Must use a different zip file otherwise it will fail because zip already contains
// title.txt and description.txt entries.
- extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT);
+ extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT, TITLE2);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
NEW_NAME2, TITLE2, DESCRIPTION2, 0, RENAMED_SCREENSHOTS);
@@ -568,7 +568,7 @@
// Send notification and click on share.
sendBugreportFinished(NO_ID, mPlainTextPath, null);
- acceptBugreport(NO_ID);
+ mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, NO_ID));
// Handle the warning
mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
@@ -725,13 +725,26 @@
return acceptBugreportAndGetSharedIntent(id);
}
+ // TODO: document / merge these 3 sendBugreportFinishedAndGetSharedIntent methods
+ private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
+ String screenshotPath, String notificationTitle) {
+ sendBugreportFinished(id, bugreportPath, screenshotPath);
+ return acceptBugreportAndGetSharedIntent(notificationTitle);
+ }
+
/**
* Accepts the notification to share the finished bugreport and waits for the result.
*
* @return extras sent in the shared intent.
*/
private Bundle acceptBugreportAndGetSharedIntent(int id) {
- acceptBugreport(id);
+ final String notificationTitle = mContext.getString(R.string.bugreport_finished_title, id);
+ return acceptBugreportAndGetSharedIntent(notificationTitle);
+ }
+
+ // TODO: document and/or merge these 2 acceptBugreportAndGetSharedIntent methods
+ private Bundle acceptBugreportAndGetSharedIntent(String notificationTitle) {
+ mUiBot.clickOnNotification(notificationTitle);
mUiBot.chooseActivity(UI_NAME);
return mListener.getExtras();
}
@@ -744,13 +757,6 @@
}
/**
- * Accepts the notification to share the finished bugreport.
- */
- private void acceptBugreport(int id) {
- mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
- }
-
- /**
* Sends a "bugreport finished" intent.
*/
private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 8fe2835..ed415b8 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -30,7 +30,6 @@
android:layout_height="wrap_content"
android:textColor="@color/clock_white"
style="@style/widget_label"
- android:textAllCaps="true"
android:letterSpacing="0.15"
android:gravity="center"
/>
@@ -41,7 +40,6 @@
android:drawableStart="@drawable/ic_access_alarms_big"
android:textColor="@color/clock_gray"
android:letterSpacing="0.15"
- android:textAllCaps="true"
style="@style/widget_label"
android:layout_marginStart="6dp"
android:gravity="center"
diff --git a/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml b/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
index 469ce52..3fb86d0 100644
--- a/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-h560dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">84dp</dimen>
+ <dimen name="widget_big_font_size">64dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
index cb89cb4..3fb86d0 100644
--- a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="widget_big_font_size">88dp</dimen>
+ <dimen name="widget_big_font_size">64dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index a3b01b6..9e788be 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -26,7 +26,7 @@
<dimen name="keyguard_security_view_margin">12dp</dimen>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">110dp</dimen>
+ <dimen name="widget_big_font_size">100dp</dimen>
<dimen name="widget_label_font_size">16sp</dimen>
<dimen name="bottom_text_spacing_digital">-1dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 210c7eb..7eb63d7 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -24,5 +24,5 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
<dimen name="keyguard_security_height">420dp</dimen>
- <dimen name="widget_big_font_size">122dp</dimen>
+ <dimen name="widget_big_font_size">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 7b952be2..3ca6e69 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -41,7 +41,7 @@
<!-- Default clock parameters -->
<dimen name="bottom_text_spacing_digital">-1dp</dimen>
<dimen name="widget_label_font_size">14sp</dimen>
- <dimen name="widget_big_font_size">78dp</dimen>
+ <dimen name="widget_big_font_size">64dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
<dimen name="appear_y_translation_start">32dp</dimen>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index fb47bbc..fb4ac04 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -35,6 +35,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp"
+ android:background="#00000000"
android:layout_marginBottom="48dp" />
<include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 65344b7..2502d41 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -24,6 +24,7 @@
android:layout_height="@dimen/status_bar_header_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:baselineAligned="false"
+ android:background="#00000000"
android:elevation="4dp"
android:clickable="false"
android:clipChildren="false"
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 6f28838..f0d7d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -16,33 +16,33 @@
package com.android.systemui.qs.tiles;
+import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
+import android.media.MediaRouter;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.Tile;
-import android.support.v7.app.MediaRouteChooserDialog;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.media.MediaControlIntent;
-import android.support.v7.media.MediaRouteSelector;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
+import com.android.internal.app.MediaRouteChooserDialog;
+import com.android.internal.app.MediaRouteControllerDialog;
+import com.android.internal.app.MediaRouteDialogPresenter;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.R.style;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -133,19 +133,12 @@
@Override
public void showDetail(boolean show) {
mUiHandler.post(() -> {
- Context context = new ContextThemeWrapper(mContext,
- R.style.Theme_AppCompat_Light_Dialog_Alert);
- if (mState.value) {
- mDialog = new MediaRouteControllerDialog(context);
- } else {
- // Instead of showing detail, show standard media routing UI.
- MediaRouteChooserDialog dialog = new MediaRouteChooserDialog(context);
- MediaRouteSelector selector = new MediaRouteSelector.Builder()
- .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
- .build();
- dialog.setRouteSelector(selector);
- mDialog = dialog;
- }
+ mDialog = MediaRouteDialogPresenter.createDialog(mContext, ROUTE_TYPE_REMOTE_DISPLAY,
+ v -> {
+ mDialog.dismiss();
+ Dependency.get(ActivityStarter.class)
+ .postStartActivityDismissingKeyguard(getLongClickIntent(), 0);
+ });
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
mUiHandler.post(() -> mDialog.show());
registerReceiver();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3a39e91..3542500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -813,10 +813,10 @@
public void onDensityOrFontScaleChanged() {
initDimens();
- if (mIsSummaryWithChildren) {
- if (mChildrenContainer != null) {
- mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
- }
+ // Let's update our childrencontainer. This is intentionally not guarded with
+ // mIsSummaryWithChildren since we might have had children but not anymore.
+ if (mChildrenContainer != null) {
+ mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
}
if (mGuts != null) {
View oldGuts = mGuts;
@@ -1458,9 +1458,11 @@
public void setUserLocked(boolean userLocked) {
mUserLocked = userLocked;
mPrivateLayout.setUserExpanding(userLocked);
- if (mIsSummaryWithChildren) {
+ // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
+ // children but not anymore.
+ if (mChildrenContainer != null) {
mChildrenContainer.setUserLocked(userLocked);
- if (userLocked || !isGroupExpanded()) {
+ if (mIsSummaryWithChildren && (userLocked || !isGroupExpanded())) {
updateBackgroundForGroupState();
}
}
@@ -2189,4 +2191,9 @@
}
}
}
+
+ @VisibleForTesting
+ protected void setChildrenContainer(NotificationChildrenContainer childrenContainer) {
+ mChildrenContainer = childrenContainer;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 78a5194..5cb3c1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -227,7 +227,7 @@
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
float notificationClipEnd;
- boolean aboveShelf = row.getTranslationZ() > baseZHeight;
+ boolean aboveShelf = ViewState.getFinalTranslationZ(row) > baseZHeight;
boolean isLastChild = child == lastChild;
float rowTranslationY = row.getTranslationY();
if (isLastChild || aboveShelf || backgroundForceHidden) {
@@ -284,10 +284,15 @@
private void updateNotificationClipHeight(ExpandableNotificationRow row,
float notificationClipEnd) {
float viewEnd = row.getTranslationY() + row.getActualHeight();
+ boolean isPinned = row.isPinned() || row.isHeadsUpAnimatingAway();
if (viewEnd > notificationClipEnd
- && (mAmbientState.isShadeExpanded()
- || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
- row.setClipBottomAmount((int) (viewEnd - notificationClipEnd));
+ && (mAmbientState.isShadeExpanded() || !isPinned)) {
+ int clipBottomAmount = (int) (viewEnd - notificationClipEnd);
+ if (isPinned) {
+ clipBottomAmount = Math.min(row.getIntrinsicHeight() - row.getCollapsedHeight(),
+ clipBottomAmount);
+ }
+ row.setClipBottomAmount(clipBottomAmount);
} else {
row.setClipBottomAmount(0);
}
@@ -381,7 +386,8 @@
? fullTransitionAmount
: transitionAmount;
iconState.clampedAppearAmount = clampedAmount;
- float contentTransformationAmount = isLastChild || iconState.translateContent
+ float contentTransformationAmount = !row.isAboveShelf()
+ && (isLastChild || iconState.translateContent)
? iconTransitionAmount
: 0.0f;
row.setContentTransformationAmount(contentTransformationAmount, isLastChild);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index c5f23c5..6b276f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -53,6 +53,7 @@
private float mInFrontTarget;
private float mBehindTarget;
private boolean mDozingAborted;
+ private boolean mWakeAndUnlocking;
public DozeScrimController(ScrimController scrimController, Context context) {
mContext = context;
@@ -63,6 +64,7 @@
public void setDozing(boolean dozing, boolean animate) {
if (mDozing == dozing) return;
mDozing = dozing;
+ mWakeAndUnlocking = false;
if (mDozing) {
mDozingAborted = false;
abortAnimations();
@@ -85,6 +87,16 @@
}
}
+ public void setWakeAndUnlocking() {
+ // Immediately abort the doze scrims in case of wake-and-unlock
+ // for pulsing so the Keyguard fade-out animation scrim can take over.
+ if (!mWakeAndUnlocking) {
+ mWakeAndUnlocking = true;
+ mScrimController.setDozeBehindAlpha(0f);
+ mScrimController.setDozeInFrontAlpha(0f);
+ }
+ }
+
/** When dozing, fade screen contents in and out using the front scrim. */
public void pulse(@NonNull DozeHost.PulseCallback callback, int reason) {
if (callback == null) {
@@ -109,7 +121,7 @@
*/
public void abortPulsing() {
cancelPulsing();
- if (mDozing) {
+ if (mDozing && !mWakeAndUnlocking) {
mScrimController.setDozeBehindAlpha(1f);
mScrimController.setDozeInFrontAlpha(
mDozeParameters.getAlwaysOn() && !mDozingAborted ? 0f : 1f);
@@ -244,6 +256,9 @@
}
private void setDozeAlpha(boolean inFront, float alpha) {
+ if (mWakeAndUnlocking) {
+ return;
+ }
if (inFront) {
mScrimController.setDozeInFrontAlpha(alpha);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index f216d6c..6cb722f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -98,7 +98,6 @@
private StatusBar mStatusBar;
private final UnlockMethodCache mUnlockMethodCache;
private final Context mContext;
- private boolean mGoingToSleep;
private int mPendingAuthenticatedUserId = -1;
public FingerprintUnlockController(Context context,
@@ -213,17 +212,19 @@
Trace.endSection();
break;
case MODE_WAKE_AND_UNLOCK_PULSING:
- Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
- mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
- true /* allowEnterAnimation */);
- // Fall through.
- Trace.endSection();
case MODE_WAKE_AND_UNLOCK:
- Trace.beginSection("MODE_WAKE_AND_UNLOCK");
+ if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
+ Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
+ mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
+ true /* allowEnterAnimation */);
+ } else {
+ Trace.beginSection("MODE_WAKE_AND_UNLOCK");
+ mDozeScrimController.abortDoze();
+ }
mStatusBarWindowManager.setStatusBarFocusable(false);
- mDozeScrimController.abortDoze();
mKeyguardViewMediator.onWakeAndUnlocking();
mScrimController.setWakeAndUnlocking();
+ mDozeScrimController.setWakeAndUnlocking();
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
}
@@ -302,10 +303,7 @@
}
private void cleanup() {
- mMode = MODE_NONE;
releaseFingerprintWakeLock();
- mStatusBarWindowManager.setForceDozeBrightness(false);
- mStatusBar.notifyFpAuthModeChanged();
}
public void startKeyguardFadingAway() {
@@ -321,6 +319,7 @@
public void finishKeyguardFadingAway() {
mMode = MODE_NONE;
+ mStatusBarWindowManager.setForceDozeBrightness(false);
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0fa8afa..af2f7e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2401,17 +2401,26 @@
@Override
public void setAlpha(float alpha) {
super.setAlpha(alpha);
- updateFullyVisibleState();
+ updateFullyVisibleState(false /* forceNotFullyVisible */);
+ }
+
+ /**
+ * Must be called before starting a ViewPropertyAnimator alpha animation because those
+ * do NOT call setAlpha and therefore don't properly update the fullyVisibleState.
+ */
+ public void notifyStartFading() {
+ updateFullyVisibleState(true /* forceNotFullyVisible */);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
- updateFullyVisibleState();
+ updateFullyVisibleState(false /* forceNotFullyVisible */);
}
- private void updateFullyVisibleState() {
- mNotificationStackScroller.setParentNotFullyVisible(getAlpha() != 1.0f
+ private void updateFullyVisibleState(boolean forceNotFullyVisible) {
+ mNotificationStackScroller.setParentNotFullyVisible(forceNotFullyVisible
+ || getAlpha() != 1.0f
|| getVisibility() != VISIBLE);
}
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 9d1d038..4b1d7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -224,6 +224,7 @@
if (mTracking) {
onTrackingStopped(true /* expanded */);
}
+ notifyExpandingFinished();
}
}
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 d798fbf..699d367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4138,6 +4138,7 @@
* fading.
*/
public void fadeKeyguardWhilePulsing() {
+ mNotificationPanel.notifyStartFading();
mNotificationPanel.animate()
.alpha(0f)
.setStartDelay(0)
@@ -4356,12 +4357,7 @@
mKeyguardIndicationController.setDozing(mDozing);
mNotificationPanel.setDark(mDozing, animate);
updateQsExpansionEnabled();
-
- // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock
- // for pulsing so the Keyguard fade-out animation scrim can take over.
- mDozeScrimController.setDozing(mDozing &&
- mFingerprintUnlockController.getMode()
- != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
+ mDozeScrimController.setDozing(mDozing, animate);
updateRowStates();
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index a31036f..bb302bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -396,6 +396,7 @@
} else {
mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
mStatusBar.finishKeyguardFadingAway();
+ mFingerprintUnlockController.finishKeyguardFadingAway();
}
}
mStatusBarWindowManager.setKeyguardShowing(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e1acc9b..e0f4429 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -18,6 +18,7 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import android.R.attr;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.Notification;
@@ -31,6 +32,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
@@ -52,6 +54,7 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
@@ -739,7 +742,12 @@
if (item.isAddUser) {
return context.getDrawable(R.drawable.ic_add_circle_qs);
}
- return UserIcons.getDefaultUserIcon(item.resolveId(), /* light= */ true);
+ Drawable icon = UserIcons.getDefaultUserIcon(item.resolveId(), /* light= */ false);
+ if (item.isGuest) {
+ icon.setColorFilter(Utils.getColorAttr(context, android.R.attr.colorForeground),
+ Mode.SRC_IN);
+ }
+ return icon;
}
public void refresh() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index cb1f44e..0dbd1d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -29,6 +29,7 @@
import android.widget.RemoteViews;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -535,8 +536,8 @@
firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
}
- boolean childrenExpanded = !mContainingNotification.isGroupExpansionChanging()
- && mChildrenExpanded;
+ boolean childrenExpandedAndNotAnimating = mChildrenExpanded
+ && !mContainingNotification.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
@@ -544,7 +545,7 @@
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
- yPosition += childrenExpanded ? mDividerHeight : mChildPadding;
+ yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (expandingToExpandedGroup) {
@@ -553,7 +554,7 @@
mNotificatonTopPadding + mDividerHeight,
expandFactor);
} else {
- yPosition += childrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
}
firstChild = false;
}
@@ -565,7 +566,7 @@
childState.hidden = false;
// When the group is expanded, the children cast the shadows rather than the parent
// so use the parent's elevation here.
- childState.zTranslation = childrenExpanded
+ childState.zTranslation = childrenExpandedAndNotAnimating
? mContainingNotification.getTranslationZ()
: 0;
childState.dimmed = parentState.dimmed;
@@ -619,7 +620,7 @@
mHeaderViewState = new ViewState();
}
mHeaderViewState.initFrom(mNotificationHeader);
- mHeaderViewState.zTranslation = childrenExpanded
+ mHeaderViewState.zTranslation = childrenExpandedAndNotAnimating
? mContainingNotification.getTranslationZ()
: 0;
}
@@ -1223,4 +1224,9 @@
}
return getGroupExpandFraction();
}
+
+ @VisibleForTesting
+ public boolean isUserLocked() {
+ return mUserLocked;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index b5db78d..12a8783 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -410,7 +410,7 @@
if (mIsExpanded) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(ambientState, row, childState);
- if (i == 0) {
+ if (i == 0 && row.isAboveShelf()) {
// the first hun can't get off screen.
clampHunToMaxTranslation(ambientState, row, childState);
}
@@ -447,10 +447,14 @@
private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
ExpandableViewState childState) {
float newTranslation;
- float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
+ float maxHeadsUpTranslation = ambientState.getMaxHeadsUpTranslation();
+ float maxShelfPosition = ambientState.getInnerHeight() + ambientState.getTopPadding()
+ + ambientState.getStackTranslation();
+ maxHeadsUpTranslation = Math.min(maxHeadsUpTranslation, maxShelfPosition);
+ float bottomPosition = maxHeadsUpTranslation - row.getCollapsedHeight();
newTranslation = Math.min(childState.yTranslation, bottomPosition);
- childState.height = (int) Math.max(childState.height
- - (childState.yTranslation - newTranslation), row.getCollapsedHeight());
+ childState.height = (int) Math.min(childState.height, maxHeadsUpTranslation
+ - newTranslation);
childState.yTranslation = newTranslation;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index d664b12..27b730cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -657,6 +657,22 @@
}
}
+ /**
+ * Get the end value of the zTranslation animation running on a view or the zTranslation
+ * if no animation is running.
+ */
+ public static float getFinalTranslationZ(View view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator zAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Z);
+ if (zAnimator == null) {
+ return view.getTranslationZ();
+ } else {
+ return getChildTag(view, TAG_END_TRANSLATION_Z);
+ }
+ }
+
public static boolean isAnimatingY(View child) {
return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
index bc79116..a3a0a6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@@ -26,6 +28,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
+import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
@@ -65,4 +69,25 @@
== View.VISIBLE);
}
+ @Test
+ public void testUserLockedResetEvenWhenNoChildren() {
+ mGroup.setUserLocked(true);
+ mGroup.removeAllChildren();
+ mGroup.setUserLocked(false);
+ Assert.assertFalse("The childrencontainer should not be userlocked but is, the state "
+ + "seems out of sync.", mGroup.getChildrenContainer().isUserLocked());
+ }
+
+ @Test
+ public void testReinflatedOnDensityChange() {
+ mGroup.setUserLocked(true);
+ mGroup.removeAllChildren();
+ mGroup.setUserLocked(false);
+ NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
+ mGroup.setChildrenContainer(mockContainer);
+ mGroup.onDensityOrFontScaleChanged();
+ verify(mockContainer).reInflateViews(any(), any());
+ }
+
+
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index debb157..564d135 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -241,6 +241,20 @@
// List of events
repeated StaEvent sta_event_list = 52;
+
+ // Total number of times WiFi HAL crashed.
+ optional int32 num_hal_crashes = 53;
+
+ // Total number of times WiFicond crashed.
+ optional int32 num_wificond_crashes = 54;
+
+ // Indicates the number of times an error was encountered in
+ // Wifi HAL when wifi was turned on.
+ optional int32 num_wifi_on_failure_due_to_hal = 55;
+
+ // Indicates the number of times an error was encountered in
+ // Wificond when wifi was turned on.
+ optional int32 num_wifi_on_failure_due_to_wificond = 56;
}
// Information that gets logged for every WiFi connection.
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index aa80075..bad8dcf 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -174,13 +174,13 @@
public void send(int resultCode, Bundle resultData) throws RemoteException {
final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
if (structure == null) {
- Slog.wtf(TAG, "no assist structure");
+ Slog.e(TAG, "No assist structure - app might have crashed providing it");
return;
}
final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
if (receiverExtras == null) {
- Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
+ Slog.e(TAG, "No receiver extras - app might have crashed providing it");
return;
}
@@ -682,7 +682,6 @@
removeSelf();
return;
}
- resetViewStatesLocked(dataset, ViewState.STATE_WAITING_DATASET_AUTH);
}
final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
@@ -1362,7 +1361,6 @@
}
// ...or handle authentication.
- // TODO(b/37424539): proper implementation
mService.setDatasetAuthenticationSelected(dataset.getId());
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntent(
@@ -1455,21 +1453,36 @@
}
try {
if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
+
// Skip null values as a null values means no change
final int entryCount = dataset.getFieldIds().size();
final List<AutofillId> ids = new ArrayList<>(entryCount);
final List<AutofillValue> values = new ArrayList<>(entryCount);
+ boolean waitingDatasetAuth = false;
for (int i = 0; i < entryCount; i++) {
if (dataset.getFieldValues().get(i) == null) {
continue;
}
- ids.add(dataset.getFieldIds().get(i));
+ final AutofillId viewId = dataset.getFieldIds().get(i);
+ ids.add(viewId);
values.add(dataset.getFieldValues().get(i));
+ final ViewState viewState = mViewStates.get(viewId);
+ if (viewState != null
+ && (viewState.getState() & ViewState.STATE_WAITING_DATASET_AUTH) != 0) {
+ if (sVerbose) {
+ Slog.v(TAG, "autofillApp(): view " + viewId + " waiting auth");
+ }
+ waitingDatasetAuth = true;
+ viewState.resetState(ViewState.STATE_WAITING_DATASET_AUTH);
+ }
}
if (!ids.isEmpty()) {
+ if (waitingDatasetAuth) {
+ hideFillUiIfOwnedByMe();
+ }
mClient.autofill(id, ids, values);
+ setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED, false);
}
- setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED, false);
} catch (RemoteException e) {
Slog.w(TAG, "Error autofilling activity: " + e);
}
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index f87fa19..8a52c96 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -174,7 +174,7 @@
* fill UI is ready to be displayed (i.e. when response and bounds are set).
*/
void maybeCallOnFillReady() {
- if ((mState & (STATE_AUTOFILLED | STATE_WAITING_DATASET_AUTH)) != 0) {
+ if ((mState & STATE_AUTOFILLED) != 0) {
if (sDebug) Slog.d(TAG, "Ignoring UI for " + id + " on " + getStateAsString());
return;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7ae4138..4b12bc4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -175,6 +175,9 @@
implements PendingIntent.OnFinished {
private static final String TAG = ConnectivityService.class.getSimpleName();
+ public static final String DIAG_ARG = "--diag";
+ public static final String SHORT_ARG = "--short";
+
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -1852,7 +1855,7 @@
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- if (argsContain(args, "--diag")) {
+ if (argsContain(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
}
@@ -1938,7 +1941,7 @@
pw.decreaseIndent();
}
- if (argsContain(args, "--short") == false) {
+ if (argsContain(args, SHORT_ARG) == false) {
pw.println();
synchronized (mValidationLogs) {
pw.println("mValidationLogs (most recent first):");
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 81a1458..901092e 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -20,6 +20,7 @@
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static com.android.server.ConnectivityService.SHORT_ARG;
import android.app.Notification;
import android.app.NotificationManager;
@@ -47,6 +48,7 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.util.SharedLog;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
@@ -62,7 +64,6 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
@@ -147,9 +148,7 @@
}
}
- private final static int MAX_LOG_RECORDS = 500;
-
- private final LocalLog mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+ private final SharedLog mLog = new SharedLog(TAG);
// used to synchronize public access to members
private final Object mPublicSync;
@@ -180,7 +179,7 @@
public Tethering(Context context, INetworkManagementService nmService,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
Looper looper, MockableSystemProperties systemProperties) {
- mLocalLog.log("CONSTRUCTED");
+ mLog.mark("constructed");
mContext = context;
mNMService = nmService;
mStatsService = statsService;
@@ -195,9 +194,9 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
- mOffloadController = new OffloadController(mTetherMasterSM.getHandler());
+ mOffloadController = new OffloadController(mTetherMasterSM.getHandler(), mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
- mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+ mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK, mLog);
mForwardedDownstreams = new HashSet<>();
mStateReceiver = new StateReceiver();
@@ -1094,7 +1093,7 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList);
+ mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
setInitialState(mInitialState);
}
@@ -1141,7 +1140,7 @@
try {
mNMService.setIpForwardingEnabled(true);
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
@@ -1154,12 +1153,12 @@
mNMService.stopTethering();
mNMService.startTethering(cfg.dhcpRanges);
} catch (Exception ee) {
- mLocalLog.log("ERROR " + ee);
+ mLog.e(ee);
transitionTo(mStartTetheringErrorState);
return false;
}
}
- mLocalLog.log("SET master tether settings: ON");
+ mLog.log("SET master tether settings: ON");
return true;
}
@@ -1167,19 +1166,19 @@
try {
mNMService.stopTethering();
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mStopTetheringErrorState);
return false;
}
try {
mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mSetIpForwardingDisabledErrorState);
return false;
}
transitionTo(mInitialState);
- mLocalLog.log("SET master tether settings: OFF");
+ mLog.log("SET master tether settings: OFF");
return true;
}
@@ -1305,13 +1304,13 @@
}
try {
mNMService.setDnsForwarders(network, dnsServers);
- mLocalLog.log(String.format(
- "SET DNS forwarders: network=%s dnsServers=[%s]",
+ mLog.log(String.format(
+ "SET DNS forwarders: network=%s dnsServers=%s",
network, Arrays.toString(dnsServers)));
} catch (Exception e) {
// TODO: Investigate how this can fail and what exactly
// happens if/when such failures occur.
- mLocalLog.log("ERROR setting DNS forwarders failed, " + e);
+ mLog.e("setting DNS forwarders failed, " + e);
transitionTo(mSetDnsForwardersErrorState);
}
}
@@ -1788,12 +1787,23 @@
pw.println("Log:");
pw.increaseIndent();
- mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
+ if (argsContain(args, SHORT_ARG)) {
+ pw.println("<log removed for brevity>");
+ } else {
+ mLog.dump(fd, pw, args);
+ }
pw.decreaseIndent();
pw.decreaseIndent();
}
+ private static boolean argsContain(String[] args, String target) {
+ for (String arg : args) {
+ if (arg.equals(target)) return true;
+ }
+ return false;
+ }
+
@Override
public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
int state, int error) {
@@ -1807,8 +1817,7 @@
}
}
- mLocalLog.log(String.format("OBSERVED iface=%s state=%s error=%s",
- iface, state, error));
+ mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
try {
// Notify that we're tethering (or not) this interface.
@@ -1846,8 +1855,8 @@
private void trackNewTetherableInterface(String iface, int interfaceType) {
TetherState tetherState;
tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
- interfaceType, mNMService, mStatsService, this,
- new IPv6TetheringInterfaceServices(iface, mNMService)));
+ interfaceType, mLog, mNMService, mStatsService, this,
+ new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
mTetherStates.put(iface, tetherState);
tetherState.stateMachine.start();
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 2485654..518f6c1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -25,6 +25,7 @@
import android.net.NetworkState;
import android.net.RouteInfo;
import android.net.util.NetworkConstants;
+import android.net.util.SharedLog;
import android.util.Log;
import java.net.Inet6Address;
@@ -64,6 +65,7 @@
}
private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final SharedLog mLog;
// NOTE: mActiveDownstreams is a list and not a hash data structure because
// we keep active downstreams in arrival order. This is done so /64s can
// be parceled out on a "first come, first served" basis and a /64 used by
@@ -74,8 +76,10 @@
private short mNextSubnetId;
private NetworkState mUpstreamNetworkState;
- public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) {
+ public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
+ SharedLog log) {
mNotifyList = notifyList;
+ mLog = log.forSubComponent(TAG);
mActiveDownstreams = new LinkedList<>();
mUniqueLocalPrefix = generateUniqueLocalPrefix();
mNextSubnetId = 0;
@@ -115,7 +119,7 @@
if (VDBG) {
Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
}
- if (!canTetherIPv6(ns)) {
+ if (!canTetherIPv6(ns, mLog)) {
stopIPv6TetheringOnAllInterfaces();
setUpstreamNetworkState(null);
return;
@@ -150,9 +154,7 @@
null);
}
- if (DBG) {
- Log.d(TAG, "setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
- }
+ mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
}
private void updateIPv6TetheringInterfaces() {
@@ -206,7 +208,7 @@
return null;
}
- private static boolean canTetherIPv6(NetworkState ns) {
+ private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
// Broadly speaking:
//
// [1] does the upstream have an IPv6 default route?
@@ -260,13 +262,11 @@
final boolean outcome = canTether && supportedConfiguration;
- if (VDBG) {
- if (ns == null) {
- Log.d(TAG, "No available upstream.");
- } else {
- Log.d(TAG, String.format("IPv6 tethering is %s for upstream: %s",
- (outcome ? "available" : "not available"), toDebugString(ns)));
- }
+ if (ns == null) {
+ sharedLog.log("No available upstream.");
+ } else {
+ sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
+ (outcome ? "available" : "not available"), toDebugString(ns)));
}
return outcome;
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index c6a7925..adf4af8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -28,10 +28,10 @@
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.NetdService;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.ServiceSpecificException;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
import java.net.Inet6Address;
@@ -54,6 +54,7 @@
private final String mIfName;
private final INetworkManagementService mNMService;
+ private final SharedLog mLog;
private NetworkInterface mNetworkInterface;
private byte[] mHwAddr;
@@ -61,9 +62,11 @@
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
- public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+ public IPv6TetheringInterfaceServices(
+ String ifname, INetworkManagementService nms, SharedLog log) {
mIfName = ifname;
mNMService = nms;
+ mLog = log.forSubComponent(mIfName);
}
public boolean start() {
@@ -72,12 +75,12 @@
try {
mNetworkInterface = NetworkInterface.getByName(mIfName);
} catch (SocketException e) {
- Log.e(TAG, "Error looking up NetworkInterfaces for " + mIfName, e);
+ mLog.e("Error looking up NetworkInterfaces: " + e);
stop();
return false;
}
if (mNetworkInterface == null) {
- Log.e(TAG, "Failed to find NetworkInterface for " + mIfName);
+ mLog.e("Failed to find NetworkInterface");
stop();
return false;
}
@@ -85,7 +88,7 @@
try {
mHwAddr = mNetworkInterface.getHardwareAddress();
} catch (SocketException e) {
- Log.e(TAG, "Failed to find hardware address for " + mIfName, e);
+ mLog.e("Failed to find hardware address: " + e);
stop();
return false;
}
@@ -161,11 +164,11 @@
try {
final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
if (removalFailures > 0) {
- Log.e(TAG, String.format("Failed to remove %d IPv6 routes from local table.",
+ mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
removalFailures));
}
} catch (RemoteException e) {
- Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e);
+ mLog.e("Failed to remove IPv6 routes from local table: " + e);
}
}
@@ -195,7 +198,7 @@
// error (EEXIST is silently ignored).
mNMService.addInterfaceToLocalNetwork(mIfName, toBeAdded);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to add IPv6 routes to local table: ", e);
+ mLog.e("Failed to add IPv6 routes to local table: " + e);
}
}
}
@@ -206,7 +209,7 @@
final INetd netd = NetdService.getInstance();
if (netd == null) {
if (newDnses != null) newDnses.clear();
- Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
+ mLog.e("No netd service instance available; not setting local IPv6 addresses");
return;
}
@@ -217,7 +220,7 @@
try {
netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
+ mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
}
}
}
@@ -234,7 +237,7 @@
try {
netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
+ mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
newDnses.remove(dns);
}
}
@@ -243,7 +246,7 @@
try {
netd.tetherApplyDnsInterfaces();
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to update local DNS caching server");
+ mLog.e("Failed to update local DNS caching server");
if (newDnses != null) newDnses.clear();
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 220e751..8f21d99 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -18,7 +18,7 @@
import android.net.LinkProperties;
import android.os.Handler;
-import android.util.Log;
+import android.net.util.SharedLog;
/**
* A wrapper around hardware offload interface.
@@ -29,16 +29,18 @@
private static final String TAG = OffloadController.class.getSimpleName();
private final Handler mHandler;
+ private final SharedLog mLog;
private LinkProperties mUpstreamLinkProperties;
- public OffloadController(Handler h) {
+ public OffloadController(Handler h, SharedLog log) {
mHandler = h;
+ mLog = log.forSubComponent(TAG);
}
public void start() {
// TODO: initOffload() and configure callbacks to be handled on our
// preferred Handler.
- Log.d(TAG, "tethering offload not supported");
+ mLog.i("tethering offload not supported");
}
public void stop() {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index d3cfd87..4a1d405 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -22,6 +22,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
@@ -82,6 +83,7 @@
private final State mTetheredState;
private final State mUnavailableState;
+ private final SharedLog mLog;
private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
private final IControlsTethering mTetherController;
@@ -93,10 +95,12 @@
private int mLastError;
private String mMyUpstreamIfaceName; // may change over time
- public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
- INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
+ public TetherInterfaceStateMachine(
+ String ifaceName, Looper looper, int interfaceType, SharedLog log,
+ INetworkManagementService nMService, INetworkStatsService statsService,
+ IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
super(ifaceName, looper);
+ mLog = log.forSubComponent(ifaceName);
mNMService = nMService;
mStatsService = statsService;
mTetherController = tetherController;
@@ -162,7 +166,7 @@
mNMService.setInterfaceConfig(mIfaceName, ifcg);
}
} catch (Exception e) {
- Log.e(TAG, "Error configuring interface " + mIfaceName, e);
+ mLog.e("Error configuring interface " + e);
return false;
}
@@ -203,7 +207,7 @@
transitionTo(mTetheredState);
break;
default:
- Log.e(TAG, "Invalid tethering interface serving state specified.");
+ mLog.e("Invalid tethering interface serving state specified.");
}
break;
case CMD_INTERFACE_DOWN:
@@ -232,13 +236,13 @@
try {
mNMService.tetherInterface(mIfaceName);
} catch (Exception e) {
- Log.e(TAG, "Error Tethering: " + e.toString());
+ mLog.e("Error Tethering: " + e);
mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
if (!mIPv6TetherSvc.start()) {
- Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
+ mLog.e("Failed to start IPv6TetheringInterfaceServices");
// TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
return;
}
@@ -255,7 +259,7 @@
mNMService.untetherInterface(mIfaceName);
} catch (Exception e) {
mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
- Log.e(TAG, "Failed to untether interface: " + e.toString());
+ mLog.e("Failed to untether interface: " + e);
}
configureIfaceIp(false);
@@ -316,7 +320,7 @@
maybeLogMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
- Log.e(TAG, "CMD_TETHER_REQUESTED while in local hotspot mode.");
+ mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
// Ignored in local hotspot state.
@@ -389,7 +393,7 @@
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
- Log.e(TAG, "CMD_TETHER_REQUESTED while already tethering.");
+ mLog.e("CMD_TETHER_REQUESTED while already tethering.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
String newUpstreamIfaceName = (String)(message.obj);
@@ -406,7 +410,7 @@
mNMService.startInterfaceForwarding(mIfaceName,
newUpstreamIfaceName);
} catch (Exception e) {
- Log.e(TAG, "Exception enabling Nat: " + e.toString());
+ mLog.e("Exception enabling NAT: " + e);
cleanupUpstreamInterface(newUpstreamIfaceName);
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
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 97a2d5e..be71490 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -29,6 +29,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.util.SharedLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -73,6 +74,7 @@
private static final int CALLBACK_MOBILE_REQUEST = 3;
private final Context mContext;
+ private final SharedLog mLog;
private final StateMachine mTarget;
private final Handler mHandler;
private final int mWhat;
@@ -84,16 +86,18 @@
private boolean mDunRequired;
private Network mCurrentDefault;
- public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
+ public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what, SharedLog log) {
mContext = ctx;
mTarget = tgt;
mHandler = mTarget.getHandler();
mWhat = what;
+ mLog = log.forSubComponent(TAG);
}
@VisibleForTesting
- public UpstreamNetworkMonitor(StateMachine tgt, int what, ConnectivityManager cm) {
- this(null, tgt, what);
+ public UpstreamNetworkMonitor(
+ StateMachine tgt, int what, ConnectivityManager cm, SharedLog log) {
+ this(null, tgt, what, log);
mCM = cm;
}
@@ -136,7 +140,7 @@
public void registerMobileNetworkRequest() {
if (mMobileNetworkCallback != null) {
- Log.e(TAG, "registerMobileNetworkRequest() already registered");
+ mLog.e("registerMobileNetworkRequest() already registered");
return;
}
@@ -156,7 +160,7 @@
// TODO: Change the timeout from 0 (no onUnavailable callback) to some
// moderate callback timeout. This might be useful for updating some UI.
// Additionally, we log a message to aid in any subsequent debugging.
- Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
+ mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
}
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
index 98771df..a91fe77 100644
--- a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -219,6 +219,7 @@
List<SubscriptionInfo> activeSubscriptionInfoList =
mSubscriptionManager.getActiveSubscriptionInfoList();
if (activeSubscriptionInfoList == null) {
+ setSimNeedsEmergencyAffordance(neededNow);
return neededNow;
}
for (SubscriptionInfo info : activeSubscriptionInfoList) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index addacce..1b32a93 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,6 +102,7 @@
import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -300,6 +301,8 @@
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
@@ -438,6 +441,21 @@
private static final int[] EMPTY_INT_ARRAY = new int[0];
+ private static final int TYPE_UNKNOWN = 0;
+ private static final int TYPE_ACTIVITY = 1;
+ private static final int TYPE_RECEIVER = 2;
+ private static final int TYPE_SERVICE = 3;
+ private static final int TYPE_PROVIDER = 4;
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_UNKNOWN,
+ TYPE_ACTIVITY,
+ TYPE_RECEIVER,
+ TYPE_SERVICE,
+ TYPE_PROVIDER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComponentType {}
+
/**
* Timeout (in milliseconds) after which the watchdog should declare that
* our handler thread is wedged. The usual default for such things is one
@@ -3499,16 +3517,25 @@
* system partition.</li>
* </ol>
*/
- private boolean canAccessInstantApps(int callingUid) {
- final boolean isSpecialProcess =
- callingUid == Process.SYSTEM_UID
- || callingUid == Process.SHELL_UID
- || callingUid == Process.ROOT_UID;
- final boolean allowMatchInstant =
- isSpecialProcess
- || mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
- return allowMatchInstant;
+ private boolean canViewInstantApps(int callingUid, int userId) {
+ if (callingUid == Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID
+ || callingUid == Process.ROOT_UID) {
+ return true;
+ }
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED) {
+ return true;
+ }
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.VIEW_INSTANT_APPS) == PERMISSION_GRANTED) {
+ final ComponentName homeComponent = getDefaultHomeActivity(userId);
+ if (homeComponent != null
+ && isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
+ return true;
+ }
+ }
+ return false;
}
private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
@@ -3527,25 +3554,8 @@
// and 2) ephemeral apps that have explicitly interacted with it
// * Ephemeral apps can only see their own data and exposed installed apps
// * Holding a signature permission allows seeing instant apps
- if (!canAccessInstantApps(callingUid)) {
- final String instantAppPackageName = getInstantAppPackageName(callingUid);
- if (instantAppPackageName != null) {
- // ephemeral apps can only get information on themselves or
- // installed apps that are exposed.
- if (!instantAppPackageName.equals(p.packageName)
- && (ps.getInstantApp(userId) || !p.visibleToInstantApps)) {
- return null;
- }
- } else {
- if (ps.getInstantApp(userId)) {
- // only get access to the ephemeral app if we've been granted access
- final int callingAppId = UserHandle.getAppId(callingUid);
- if (!mInstantAppRegistry.isInstantAccessGranted(
- userId, callingAppId, ps.appId)) {
- return null;
- }
- }
- }
+ if (filterAppAccessLPr(ps, callingUid, userId)) {
+ return null;
}
final PermissionsState permissionsState = ps.getPermissionsState();
@@ -3705,6 +3715,47 @@
return null;
}
+ private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
+ if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
+ return true;
+ }
+ if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
+ return true;
+ }
+ if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isComponentVisibleToInstantApp(
+ @Nullable ComponentName component, @ComponentType int type) {
+ if (type == TYPE_ACTIVITY) {
+ final PackageParser.Activity activity = mActivities.mActivities.get(component);
+ return activity != null
+ ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ : false;
+ } else if (type == TYPE_RECEIVER) {
+ final PackageParser.Activity activity = mReceivers.mActivities.get(component);
+ return activity != null
+ ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ : false;
+ } else if (type == TYPE_SERVICE) {
+ final PackageParser.Service service = mServices.mServices.get(component);
+ return service != null
+ ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ : false;
+ } else if (type == TYPE_PROVIDER) {
+ final PackageParser.Provider provider = mProviders.mProviders.get(component);
+ return provider != null
+ ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+ : false;
+ } else if (type == TYPE_UNKNOWN) {
+ return isComponentVisibleToInstantApp(component);
+ }
+ return false;
+ }
+
/**
* Returns whether or not access to the application should be filtered.
* <p>
@@ -3714,7 +3765,7 @@
* @see #canAccessInstantApps(int)
*/
private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid,
- @Nullable ComponentName component, boolean componentVisibleToInstantApp, int userId) {
+ @Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
callingUid = mIsolatedOwners.get(callingUid);
@@ -3735,14 +3786,14 @@
if (callerIsInstantApp) {
// request for a specific component; if it hasn't been explicitly exposed, filter
if (component != null) {
- return !componentVisibleToInstantApp;
+ return !isComponentVisibleToInstantApp(component, componentType);
}
// request for application; if no components have been explicitly exposed, filter
- return !ps.pkg.visibleToInstantApps;
+ return ps.getInstantApp(userId) || !ps.pkg.visibleToInstantApps;
}
if (ps.getInstantApp(userId)) {
// caller can see all components of all instant applications, don't filter
- if (canAccessInstantApps(callingUid)) {
+ if (canViewInstantApps(callingUid, userId)) {
return false;
}
// request for a specific instant application component, filter
@@ -3760,7 +3811,7 @@
* @see #filterAppAccessLPr(PackageSetting, int, ComponentName, boolean, int)
*/
private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid, int userId) {
- return filterAppAccessLPr(ps, callingUid, null, false, userId);
+ return filterAppAccessLPr(ps, callingUid, null, TYPE_UNKNOWN, userId);
}
private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
@@ -4366,11 +4417,12 @@
flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
flags |= PackageManager.MATCH_INSTANT;
} else {
+ final boolean wantMatchInstant = (flags & PackageManager.MATCH_INSTANT) != 0;
final boolean allowMatchInstant =
(wantInstantApps
&& Intent.ACTION_VIEW.equals(intent.getAction())
&& hasWebURI(intent))
- || canAccessInstantApps(callingUid);
+ || (wantMatchInstant && canViewInstantApps(callingUid, userId));
flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
| PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
if (!allowMatchInstant) {
@@ -4412,9 +4464,7 @@
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- final boolean visibleToInstantApp =
- (a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
- if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
@@ -4445,9 +4495,7 @@
if (ps == null) {
return false;
}
- final boolean visibleToInstantApp =
- (a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
- if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, callingUserId)) {
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
return false;
}
for (int i=0; i<a.intents.size(); i++) {
@@ -4463,8 +4511,9 @@
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -4473,6 +4522,9 @@
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
+ return null;
+ }
return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
}
}
@@ -4606,9 +4658,7 @@
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- final boolean visibleToInstantApp =
- (s.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
- if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
@@ -4636,9 +4686,7 @@
if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
- final boolean visibleToInstantApp =
- (p.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
- if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
@@ -5899,7 +5947,7 @@
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mPackages) {
- if (canAccessInstantApps(callingUid)) {
+ if (canViewInstantApps(callingUid, callingUserId)) {
return new ArrayList<String>(mPackages.keySet());
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
@@ -7553,6 +7601,7 @@
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
+ final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, intent, callingUid,
false /*includeInstantApps*/);
ComponentName comp = intent.getComponent();
@@ -7563,26 +7612,61 @@
}
}
if (comp != null) {
- List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- ActivityInfo ai = getReceiverInfo(comp, flags, userId);
+ final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
if (ai != null) {
- ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = ai;
- list.add(ri);
+ // When specifying an explicit component, we prevent the activity from being
+ // used when either 1) the calling package is normal and the activity is within
+ // an instant application or 2) the calling package is ephemeral and the
+ // activity is not visible to instant applications.
+ final boolean matchInstantApp =
+ (flags & PackageManager.MATCH_INSTANT) != 0;
+ final boolean matchVisibleToInstantAppOnly =
+ (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
+ final boolean matchExplicitlyVisibleOnly =
+ (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
+ final boolean isCallerInstantApp =
+ instantAppPkgName != null;
+ final boolean isTargetSameInstantApp =
+ comp.getPackageName().equals(instantAppPkgName);
+ final boolean isTargetInstantApp =
+ (ai.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+ final boolean isTargetVisibleToInstantApp =
+ (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ final boolean isTargetExplicitlyVisibleToInstantApp =
+ isTargetVisibleToInstantApp
+ && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+ final boolean isTargetHiddenFromInstantApp =
+ !isTargetVisibleToInstantApp
+ || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp);
+ final boolean blockResolution =
+ !isTargetSameInstantApp
+ && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
+ || (matchVisibleToInstantAppOnly && isCallerInstantApp
+ && isTargetHiddenFromInstantApp));
+ if (!blockResolution) {
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ list.add(ri);
+ }
}
- return list;
+ return applyPostResolutionFilter(list, instantAppPkgName);
}
// reader
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
- return mReceivers.queryIntent(intent, resolvedType, flags, userId);
+ final List<ResolveInfo> result =
+ mReceivers.queryIntent(intent, resolvedType, flags, userId);
+ return applyPostResolutionFilter(result, instantAppPkgName);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
- userId);
+ final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
+ intent, resolvedType, flags, pkg.receivers, userId);
+ return applyPostResolutionFilter(result, instantAppPkgName);
}
return Collections.emptyList();
}
@@ -8072,9 +8156,7 @@
final boolean returnAllowed =
ps != null
&& (isCallerSameApp(packageName, callingUid)
- || mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_INSTANT_APPS)
- == PERMISSION_GRANTED
+ || canViewInstantApps(callingUid, userId)
|| mInstantAppRegistry.isInstantAccessGranted(
userId, UserHandle.getAppId(callingUid), ps.appId));
if (returnAllowed) {
@@ -8263,11 +8345,11 @@
@Override
public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
int uid, int flags, String metaDataKey) {
+ final int callingUid = Binder.getCallingUid();
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForComponent(flags, userId, processName);
-
ArrayList<ProviderInfo> finalList = null;
// reader
synchronized (mPackages) {
@@ -8287,7 +8369,11 @@
&& (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
continue;
}
-
+ final ComponentName component =
+ new ComponentName(p.info.packageName, p.info.name);
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
+ continue;
+ }
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
@@ -8309,10 +8395,17 @@
}
@Override
- public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
+ public InstrumentationInfo getInstrumentationInfo(ComponentName component, int flags) {
// reader
synchronized (mPackages) {
- final PackageParser.Instrumentation i = mInstrumentation.get(name);
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ if (ps == null) return null;
+ if (filterAppAccessLPr(ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
+ return null;
+ }
+ final PackageParser.Instrumentation i = mInstrumentation.get(component);
return PackageParser.generateInstrumentationInfo(i, flags);
}
}
@@ -8320,6 +8413,12 @@
@Override
public @NonNull ParceledListSlice<InstrumentationInfo> queryInstrumentation(
String targetPackage, int flags) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final PackageSetting ps = mSettings.mPackages.get(targetPackage);
+ if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
+ return ParceledListSlice.emptyList();
+ }
return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
}
@@ -9106,8 +9205,16 @@
@Override
public void notifyPackageUse(String packageName, int reason) {
synchronized (mPackages) {
- if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
- return;
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (getInstantAppPackageName(callingUid) != null) {
+ if (!isCallerSameApp(packageName, callingUid)) {
+ return;
+ }
+ } else {
+ if (isInstantApp(packageName, callingUserId)) {
+ return;
+ }
}
final PackageParser.Package p = mPackages.get(packageName);
if (p == null) {
@@ -21004,14 +21111,17 @@
}
@Override
- public int getComponentEnabledSetting(ComponentName componentName, int userId) {
+ public int getComponentEnabledSetting(ComponentName component, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
- int uid = Binder.getCallingUid();
- enforceCrossUserPermission(uid, userId,
- false /* requireFullPermission */, false /* checkShell */, "get component enabled");
- // reader
+ int callingUid = Binder.getCallingUid();
+ enforceCrossUserPermission(callingUid, userId,
+ false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
synchronized (mPackages) {
- return mSettings.getComponentEnabledSettingLPr(componentName, userId);
+ if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
+ component, TYPE_UNKNOWN, userId)) {
+ return COMPONENT_ENABLED_STATE_DISABLED;
+ }
+ return mSettings.getComponentEnabledSettingLPr(component, userId);
}
}
@@ -24279,8 +24389,8 @@
}
@Override
- public boolean canAccessInstantApps(int callingUid) {
- return PackageManagerService.this.canAccessInstantApps(callingUid);
+ public boolean canAccessInstantApps(int callingUid, int userId) {
+ return PackageManagerService.this.canViewInstantApps(callingUid, userId);
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a8d19e9..c8ade2d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3122,10 +3122,6 @@
if (reason == null) {
reason = "";
}
- if (reason.equals(PowerManager.REBOOT_RECOVERY)
- || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
- reason = "recovery";
- }
// If the reason is "quiescent", it means that the boot process should proceed
// without turning on the screen/lights.
@@ -3134,6 +3130,15 @@
if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
sQuiescent = true;
reason = "";
+ } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
+ sQuiescent = true;
+ reason = reason.substring(0,
+ reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
+ }
+
+ if (reason.equals(PowerManager.REBOOT_RECOVERY)
+ || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ reason = "recovery";
}
if (sQuiescent) {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 65e3ec0..f769261 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -78,6 +78,9 @@
// requires that the duration of the two animations are the same.
SurfaceControl thumbnail;
int thumbnailTransactionSeq;
+ // TODO(b/62029108): combine both members into a private one. Create a member function to set
+ // the thumbnail layer to +1 to the highest layer position and replace all setter instances
+ // with this function. Remove all unnecessary calls to both variables in other classes.
int thumbnailLayer;
int thumbnailForceAboveLayer;
Animation thumbnailAnimation;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 17db253..f0e0e14 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -341,7 +341,9 @@
boolean delayed = false;
inPendingTransaction = false;
-
+ // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
+ // been set by the app now.
+ mHiddenSetFromTransferredStartingWindow = false;
setClientHidden(!visible);
// Allow for state changes and animation to be applied if:
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 172ec48..01a3143 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -257,9 +257,20 @@
w.mLayer = layer;
w.mWinAnimator.mAnimLayer = w.getAnimLayerAdjustment()
+ w.getSpecialWindowAnimLayerAdjustment();
- if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0
- && w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
- w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
+ if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0) {
+ if (w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
+ w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
+ }
+ // TODO(b/62029108): the entire contents of the if statement should call the refactored
+ // function to set the thumbnail layer for w.AppToken
+ int highestLayer = w.mAppToken.getHighestAnimLayer();
+ if (highestLayer > 0) {
+ if (w.mAppToken.mAppAnimator.thumbnail != null
+ && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer != highestLayer) {
+ w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = highestLayer;
+ w.mAppToken.mAppAnimator.thumbnail.setLayer(highestLayer + 1);
+ }
+ }
}
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b620b3e..1d44a205 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -671,7 +671,6 @@
VibratorService vibrator = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
- IpSecService ipSecService = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
@@ -1024,15 +1023,6 @@
reportWtf("starting NetworkManagement Service", e);
}
traceEnd();
-
- traceBeginAndSlog("StartIpSecService");
- try {
- ipSecService = IpSecService.create(context);
- ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
- } catch (Throwable e) {
- reportWtf("starting IpSec Service", e);
- }
- traceEnd();
}
if (!disableNonCoreServices && !disableTextServices) {
@@ -1643,7 +1633,6 @@
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
- final IpSecService ipSecServiceF = ipSecService;
final WindowManagerService windowManagerF = wm;
// We now tell the activity manager it is okay to run third party
@@ -1708,13 +1697,6 @@
.networkScoreAndNetworkManagementServiceReady();
}
traceEnd();
- traceBeginAndSlog("MakeIpSecServiceReady");
- try {
- if (ipSecServiceF != null) ipSecServiceF.systemReady();
- } catch (Throwable e) {
- reportWtf("making IpSec Service ready", e);
- }
- traceEnd();
traceBeginAndSlog("MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) networkStatsF.systemReady();
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
new file mode 100644
index 0000000..343d237
--- /dev/null
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -0,0 +1,132 @@
+/*
+ * 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.util;
+
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.StringJoiner;
+
+
+/**
+ * Class to centralize logging functionality for tethering.
+ *
+ * All access to class methods other than dump() must be on the same thread.
+ *
+ * @hide
+ */
+public class SharedLog {
+ private final static int DEFAULT_MAX_RECORDS = 500;
+ private final static String COMPONENT_DELIMITER = ".";
+
+ private enum Category {
+ NONE,
+ ERROR,
+ MARK,
+ WARN,
+ };
+
+ private final LocalLog mLocalLog;
+ // The tag to use for output to the system log. This is not output to the
+ // LocalLog because that would be redundant.
+ private final String mTag;
+ // The component (or subcomponent) of a system that is sharing this log.
+ // This can grow in depth if components call forSubComponent() to obtain
+ // their SharedLog instance. The tag is not included in the component for
+ // brevity.
+ private final String mComponent;
+
+ public SharedLog(String tag) {
+ this(DEFAULT_MAX_RECORDS, tag);
+ }
+
+ public SharedLog(int maxRecords, String tag) {
+ this(new LocalLog(maxRecords), tag, tag);
+ }
+
+ private SharedLog(LocalLog localLog, String tag, String component) {
+ mLocalLog = localLog;
+ mTag = tag;
+ mComponent = component;
+ }
+
+ public SharedLog forSubComponent(String component) {
+ if (!isRootLogInstance()) {
+ component = mComponent + COMPONENT_DELIMITER + component;
+ }
+ return new SharedLog(mLocalLog, mTag, component);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
+ }
+
+ //////
+ // Methods that both log an entry and emit it to the system log.
+ //////
+
+ public void e(Exception e) {
+ Log.e(mTag, record(Category.ERROR, e.toString()));
+ }
+
+ public void e(String msg) {
+ Log.e(mTag, record(Category.ERROR, msg));
+ }
+
+ public void i(String msg) {
+ Log.i(mTag, record(Category.NONE, msg));
+ }
+
+ public void w(String msg) {
+ Log.w(mTag, record(Category.WARN, msg));
+ }
+
+ //////
+ // Methods that only log an entry (and do NOT emit to the system log).
+ //////
+
+ public void log(String msg) {
+ record(Category.NONE, msg);
+ }
+
+ public void mark(String msg) {
+ record(Category.MARK, msg);
+ }
+
+ private String record(Category category, String msg) {
+ final String entry = logLine(category, msg);
+ mLocalLog.log(entry);
+ return entry;
+ }
+
+ private String logLine(Category category, String msg) {
+ final StringJoiner sj = new StringJoiner(" ");
+ if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
+ if (category != Category.NONE) sj.add(category.toString());
+ return sj.add(msg).toString();
+ }
+
+ // Check whether this SharedLog instance is nominally the top level in
+ // a potential hierarchy of shared logs (the root of a tree),
+ // or is a subcomponent within the hierarchy.
+ private boolean isRootLogInstance() {
+ return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 32eee84..6618a69 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -115,6 +115,10 @@
"mChildAppWindowAbove");
mChildAppWindowBelow = createCommonWindow(mAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
"mChildAppWindowBelow");
+
+ // Adding a display will cause freezing the display. Make sure to wait until it's unfrozen
+ // to not run into race conditions with the tests.
+ waitUntilHandlersIdle();
}
@After
@@ -135,6 +139,9 @@
mDisplayContent.removeImmediately();
sWm.mInputMethodTarget = null;
}
+
+ // Wait until everything is really cleaned up.
+ waitUntilHandlersIdle();
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 912e7a8..073a17e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -411,8 +411,8 @@
}
}
- private boolean shouldObfuscateInstantAppsForCaller(int callingUid) {
- return !mPackageManagerInternal.canAccessInstantApps(callingUid);
+ private boolean shouldObfuscateInstantAppsForCaller(int callingUid, int userId) {
+ return !mPackageManagerInternal.canAccessInstantApps(callingUid, userId);
}
void clearAppIdleForPackage(String packageName, int userId) {
@@ -1390,7 +1390,7 @@
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
- Binder.getCallingUid());
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
@@ -1435,7 +1435,7 @@
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
- Binder.getCallingUid());
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
@@ -1456,7 +1456,7 @@
throw re.rethrowFromSystemServer();
}
final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
- Binder.getCallingUid());
+ Binder.getCallingUid(), userId);
final long token = Binder.clearCallingIdentity();
try {
return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId,
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
new file mode 100644
index 0000000..7fd7a63
--- /dev/null
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Vector;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SharedLogTest {
+ private static final String TIMESTAMP_PATTERN =
+ "^[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]";
+ private static final String TIMESTAMP = "mm-dd HH:MM:SS.xxx";
+
+ @Test
+ public void testBasicOperation() {
+ final SharedLog logTop = new SharedLog("top");
+ logTop.mark("first post!");
+
+ final SharedLog logLevel2a = logTop.forSubComponent("twoA");
+ final SharedLog logLevel2b = logTop.forSubComponent("twoB");
+ logLevel2b.e("2b or not 2b");
+ logLevel2a.w("second post?");
+
+ final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
+ logTop.log("still logging");
+ logLevel3.log("3 >> 2");
+ logLevel2a.mark("ok: last post");
+
+ final String[] expected = {
+ TIMESTAMP + " - MARK first post!",
+ TIMESTAMP + " - [twoB] ERROR 2b or not 2b",
+ TIMESTAMP + " - [twoA] WARN second post?",
+ TIMESTAMP + " - still logging",
+ TIMESTAMP + " - [twoA.three] 3 >> 2",
+ TIMESTAMP + " - [twoA] MARK ok: last post",
+ };
+ // Verify the logs are all there and in the correct order.
+ verifyLogLines(expected, logTop);
+
+ // In fact, because they all share the same underlying LocalLog,
+ // every subcomponent SharedLog's dump() is identical.
+ verifyLogLines(expected, logLevel2a);
+ verifyLogLines(expected, logLevel2b);
+ verifyLogLines(expected, logLevel3);
+ }
+
+ private static void verifyLogLines(String[] expected, SharedLog log) {
+ final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+ final PrintWriter pw = new PrintWriter(ostream, true);
+ log.dump(null, pw, null);
+
+ final String dumpOutput = ostream.toString();
+ assertTrue(dumpOutput != null);
+ assertTrue(!"".equals(dumpOutput));
+
+ final String[] lines = dumpOutput.split("\n");
+ assertEquals(expected.length, lines.length);
+
+ for (int i = 0; i < lines.length; i++) {
+ // Fix up the timestamps.
+ lines[i] = lines[i].replaceAll(TIMESTAMP_PATTERN, TIMESTAMP);
+ }
+
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], lines[i]);
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index a3f33dc..27e683c 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -38,6 +38,7 @@
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -63,12 +64,14 @@
@Mock private IControlsTethering mTetherHelper;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
+ @Mock private SharedLog mSharedLog;
private final TestLooper mLooper = new TestLooper();
private TetherInterfaceStateMachine mTestedSm;
private void initStateMachine(int interfaceType) throws Exception {
- mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
+ mTestedSm = new TetherInterfaceStateMachine(
+ IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
@@ -90,12 +93,13 @@
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
}
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index c72efb0..9bb392a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -25,11 +25,13 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
@@ -40,6 +42,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.util.SharedLog;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -69,6 +72,7 @@
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
+ @Mock private SharedLog mLog;
private TestStateMachine mSM;
private TestConnectivityManager mCM;
@@ -78,10 +82,12 @@
MockitoAnnotations.initMocks(this);
reset(mContext);
reset(mCS);
+ reset(mLog);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
mCM = spy(new TestConnectivityManager(mContext, mCS));
mSM = new TestStateMachine();
- mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM, mLog);
}
@After public void tearDown() throws Exception {