Merge "Adding a comment specifying the timebase for emergency call time"
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 124749a..f719749 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -93,6 +93,7 @@
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
+import android.os.Debug;
import android.os.DropBoxManager;
import android.os.HardwarePropertiesManager;
import android.os.IBatteryPropertiesRegistrar;
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index bb844a3..919f4ba 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A request for the user to select a companion device to associate with.
@@ -69,6 +70,20 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AssociationRequest that = (AssociationRequest) o;
+ return mSingleDevice == that.mSingleDevice &&
+ Objects.equals(mDeviceFilters, that.mDeviceFilters);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSingleDevice, mDeviceFilters);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (mSingleDevice ? 1 : 0));
dest.writeParcelableList(mDeviceFilters, flags);
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index 1d8df7f..84e1536 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -35,6 +35,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -123,6 +124,22 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BluetoothDeviceFilter that = (BluetoothDeviceFilter) o;
+ return Objects.equals(mNamePattern, that.mNamePattern) &&
+ Objects.equals(mAddress, that.mAddress) &&
+ Objects.equals(mServiceUuids, that.mServiceUuids) &&
+ Objects.equals(mServiceUuidMasks, that.mServiceUuidMasks);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern, mAddress, mServiceUuids, mServiceUuidMasks);
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index e057fbc..0444775 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -36,6 +36,8 @@
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -160,9 +162,39 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BluetoothLEDeviceFilter that = (BluetoothLEDeviceFilter) o;
+ return mRenameBytesFrom == that.mRenameBytesFrom &&
+ mRenameBytesTo == that.mRenameBytesTo &&
+ mRenameBytesReverseOrder == that.mRenameBytesReverseOrder &&
+ Objects.equals(mNamePattern, that.mNamePattern) &&
+ Objects.equals(mScanFilter, that.mScanFilter) &&
+ Arrays.equals(mRawDataFilter, that.mRawDataFilter) &&
+ Arrays.equals(mRawDataFilterMask, that.mRawDataFilterMask) &&
+ Objects.equals(mRenamePrefix, that.mRenamePrefix) &&
+ Objects.equals(mRenameSuffix, that.mRenameSuffix);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask,
+ mRenamePrefix, mRenameSuffix, mRenameBytesFrom, mRenameBytesTo,
+ mRenameBytesReverseOrder);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(patternToString(getNamePattern()));
dest.writeParcelable(mScanFilter, flags);
+ dest.writeByteArray(mRawDataFilter);
+ dest.writeByteArray(mRawDataFilterMask);
+ dest.writeString(mRenamePrefix);
+ dest.writeString(mRenameSuffix);
+ dest.writeInt(mRenameBytesFrom);
+ dest.writeInt(mRenameBytesTo);
+ dest.writeBoolean(mRenameBytesReverseOrder);
}
@Override
@@ -174,13 +206,23 @@
= new Creator<BluetoothLEDeviceFilter>() {
@Override
public BluetoothLEDeviceFilter createFromParcel(Parcel in) {
- return new BluetoothLEDeviceFilter.Builder()
+ Builder builder = new Builder()
.setNamePattern(patternFromString(in.readString()))
- .setScanFilter(in.readParcelable(null))
- .setRawDataFilter(in.readBlob(), in.readBlob())
- .setRename(in.readString(), in.readString(),
- in.readInt(), in.readInt(), in.readBoolean())
- .build();
+ .setScanFilter(in.readParcelable(null));
+ byte[] rawDataFilter = in.createByteArray();
+ byte[] rawDataFilterMask = in.createByteArray();
+ if (rawDataFilter != null) {
+ builder.setRawDataFilter(rawDataFilter, rawDataFilterMask);
+ }
+ String renamePrefix = in.readString();
+ String suffix = in.readString();
+ int bytesFrom = in.readInt();
+ int bytesTo = in.readInt();
+ boolean bytesReverseOrder = in.readBoolean();
+ if (renamePrefix != null) {
+ builder.setRename(renamePrefix, suffix, bytesFrom, bytesTo, bytesReverseOrder);
+ }
+ return builder.build();
}
@Override
@@ -240,12 +282,14 @@
*/
@NonNull
public Builder setRawDataFilter(@NonNull byte[] rawDataFilter,
- @NonNull byte[] rawDataFilterMask) {
+ @Nullable byte[] rawDataFilterMask) {
checkNotUsed();
- checkArgument(rawDataFilter.length == rawDataFilterMask.length,
+ Preconditions.checkNotNull(rawDataFilter);
+ checkArgument(rawDataFilterMask == null ||
+ rawDataFilter.length == rawDataFilterMask.length,
"Mask and filter should be the same length");
- mRawDataFilter = Preconditions.checkNotNull(rawDataFilter);
- mRawDataFilterMask = Preconditions.checkNotNull(rawDataFilterMask);
+ mRawDataFilter = rawDataFilter;
+ mRawDataFilterMask = rawDataFilterMask;
return this;
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 78e3de4..7b38863 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -17,6 +17,8 @@
package android.companion;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -24,7 +26,6 @@
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -43,7 +44,7 @@
*/
public final class CompanionDeviceManager {
- private static final boolean DEBUG = false; //TODO
+ private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManager";
/**
@@ -129,10 +130,9 @@
if (!checkFeaturePresent()) {
return;
}
-
- final Handler finalHandler = handler != null
- ? handler
- : new Handler(Looper.getMainLooper());
+ checkNotNull(request, "Request cannot be null");
+ checkNotNull(callback, "Callback cannot be null");
+ final Handler finalHandler = Handler.mainIfNull(handler);
try {
mService.associate(
request,
diff --git a/core/java/android/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 1ab9ce1..b6e704c 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.provider.OneTimeUseBuilder;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -75,6 +76,19 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WifiDeviceFilter that = (WifiDeviceFilter) o;
+ return Objects.equals(mNamePattern, that.mNamePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(patternToString(getNamePattern()));
}
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 60b27b4..0448221 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -16,6 +16,7 @@
package android.metrics;
import android.annotation.SystemApi;
+import android.content.ComponentName;
import android.util.Log;
import android.util.SparseArray;
@@ -118,6 +119,16 @@
return this;
}
+ /**
+ * @param component to replace the existing setting.
+ * @hide
+ */
+ public LogMaker setComponentName(ComponentName component) {
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, component.getPackageName());
+ entries.put(MetricsEvent.FIELD_CLASS_NAME, component.getClassName());
+ return this;
+ }
+
/** Remove the package name property. */
public LogMaker clearPackageName() {
entries.remove(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 3c7c962..8678d95 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import android.util.Printer;
@@ -69,6 +71,7 @@
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
+ private static Handler MAIN_THREAD_HANDLER = null;
/**
* Callback interface you can use when instantiating a Handler to avoid
@@ -231,6 +234,21 @@
mAsynchronous = async;
}
+ /** @hide */
+ @NonNull
+ public static Handler getMain() {
+ if (MAIN_THREAD_HANDLER == null) {
+ MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
+ }
+ return MAIN_THREAD_HANDLER;
+ }
+
+ /** @hide */
+ @NonNull
+ public static Handler mainIfNull(@Nullable Handler handler) {
+ return handler == null ? getMain() : handler;
+ }
+
/** {@hide} */
public String getTraceName(Message message) {
final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index 87231e1..44019c32 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -17,6 +17,7 @@
package android.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.ParcelableException;
import com.android.internal.util.Preconditions;
@@ -55,10 +56,26 @@
return getCompleteMessage(null, t);
}
+ public static <E extends Throwable> void propagateIfInstanceOf(
+ @Nullable Throwable t, Class<E> c) throws E {
+ if (t != null && c.isInstance(t)) {
+ throw c.cast(t);
+ }
+ }
+
+ /**
+ * @param <E> a checked exception that is ok to throw without wrapping
+ */
+ public static <E extends Exception> RuntimeException propagate(@NonNull Throwable t, Class<E> c)
+ throws E {
+ propagateIfInstanceOf(t, c);
+ return propagate(t);
+ }
+
public static RuntimeException propagate(@NonNull Throwable t) {
Preconditions.checkNotNull(t);
- if (t instanceof Error) throw (Error)t;
- if (t instanceof RuntimeException) throw (RuntimeException)t;
+ propagateIfInstanceOf(t, Error.class);
+ propagateIfInstanceOf(t, RuntimeException.class);
throw new RuntimeException(t);
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index b63b899..7d243af 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -2178,9 +2178,14 @@
update = true;
}
- final View anchor = mAnchor.get();
- final int newAccessibilityIdOfAnchor = (anchor != null)
- ? anchor.getAccessibilityViewId() : -1;
+ View anchor = null;
+ int newAccessibilityIdOfAnchor = -1;
+
+ if (mAnchor != null && mAnchor.get() != null) {
+ anchor = mAnchor.get();
+ newAccessibilityIdOfAnchor = anchor.getAccessibilityViewId();
+ }
+
if (newAccessibilityIdOfAnchor != p.accessibilityIdOfAnchor) {
p.accessibilityIdOfAnchor = newAccessibilityIdOfAnchor;
update = true;
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index e8972aa..d154730 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -363,6 +363,7 @@
state.computedState.transform.copyTo(&info.transform[0]);
mRenderState.invokeFunctor(op.functor, DrawGlInfo::kModeDraw, &info);
+ if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index e49463f..1b6aca1 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -58,6 +58,7 @@
import android.widget.ArrayAdapter;
import android.widget.TextView;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.Preconditions;
@@ -180,15 +181,20 @@
}
private void startDiscovery(AssociationRequest request) {
- mRequest = request;
+ if (!request.equals(mRequest)) {
+ mRequest = request;
- mFilters = request.getDeviceFilters();
- mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
- mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
- mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLEDeviceFilter.class);
- mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
+ mFilters = request.getDeviceFilters();
+ mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class);
+ mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class);
+ mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLEDeviceFilter.class);
+ mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
- reset();
+ reset();
+ }
+ if (!ArrayUtils.isEmpty(mDevicesFound)) {
+ onReadyToShowUI();
+ }
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
@@ -228,10 +234,18 @@
private void stopScan() {
if (DEBUG) Log.i(LOG_TAG, "stopScan() called");
- mBluetoothAdapter.cancelDiscovery();
- mBLEScanner.stopScan(mBLEScanCallback);
- unregisterReceiver(mBluetoothDeviceFoundBroadcastReceiver);
- unregisterReceiver(mWifiDeviceFoundBroadcastReceiver);
+
+ if (shouldScan(mBluetoothFilters)) {
+ mBluetoothAdapter.cancelDiscovery();
+ unregisterReceiver(mBluetoothDeviceFoundBroadcastReceiver);
+ }
+ if (shouldScan(mBLEFilters)) {
+ mBLEScanner.stopScan(mBLEScanCallback);
+ }
+ if (shouldScan(mWifiFilters)) {
+ unregisterReceiver(mWifiDeviceFoundBroadcastReceiver);
+ }
+
stopSelf();
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d058e78..79190cb 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -24,6 +24,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.NightDisplayController;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.assist.AssistManager;
@@ -257,6 +258,8 @@
mProviders.put(VolumeDialogController.class, () ->
new VolumeDialogControllerImpl(mContext));
+ mProviders.put(MetricsLogger.class, () -> new MetricsLogger());
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index f70d5b4..b689a850 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -104,6 +104,8 @@
private int mImeHeight;
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
+ private boolean mMovementWithinMinimize;
+ private boolean mMovementWithinDismiss;
// Touch state
private final PipTouchState mTouchState;
@@ -435,6 +437,8 @@
* Gesture controlling normal movement of the PIP.
*/
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
+ // Whether the PiP was on the left side of the screen at the start of the gesture
+ private boolean mStartedOnLeft;
@Override
public void onDown(PipTouchState touchState) {
@@ -442,6 +446,10 @@
return;
}
+ mStartedOnLeft = mMotionHelper.getBounds().left < mMovementBounds.centerX();
+ mMovementWithinMinimize = true;
+ mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
+
// If the menu is still visible, and we aren't minimized, then just poke the menu
// so that it will timeout after the user stops touching it
if (mMenuController.isMenuVisible() && !mIsMinimized) {
@@ -493,6 +501,18 @@
if (ENABLE_DISMISS_DRAG_TO_EDGE) {
updateDismissFraction();
}
+
+ final PointF curPos = touchState.getLastTouchPosition();
+ if (mMovementWithinMinimize) {
+ // Track if movement remains near starting edge to identify swipes to minimize
+ mMovementWithinMinimize = mStartedOnLeft
+ ? curPos.x <= mMovementBounds.left + mTmpBounds.width()
+ : curPos.x >= mMovementBounds.right;
+ }
+ if (mMovementWithinDismiss) {
+ // Track if movement remains near the bottom edge to identify swipe to dismiss
+ mMovementWithinDismiss = curPos.y >= mMovementBounds.bottom;
+ }
return true;
}
return false;
@@ -526,8 +546,15 @@
}
if (touchState.isDragging()) {
+ final PointF vel = touchState.getVelocity();
+ final float velocity = PointF.length(vel.x, vel.y);
+ final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond();
+ final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
final boolean onLeft = mMotionHelper.getBounds().left < mMovementBounds.centerX();
- boolean isFlingToBot = isFlingTowardsEdge(touchState, 4 /* bottom */);
+ final boolean isFlingToBot = !isHorizontal && mMovementWithinDismiss && vel.y > 0;
+ final boolean isFlingToEdge = isHorizontal && mMovementWithinMinimize
+ && (onLeft ? vel.x < 0 : vel.x > 0);
+
if (ENABLE_DISMISS_DRAG_TO_EDGE
&& (mMotionHelper.shouldDismissPip() || isFlingToBot)) {
mMotionHelper.animateDragToEdgeDismiss(mMotionHelper.getBounds(),
@@ -536,8 +563,7 @@
MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
METRIC_VALUE_DISMISSED_BY_DRAG);
return true;
- } else if (!mIsMinimized && (mMotionHelper.shouldMinimizePip()
- || isFlingTowardsEdge(touchState, onLeft ? 2 : 3))) {
+ } else if (!mIsMinimized && (mMotionHelper.shouldMinimizePip() || isFlingToEdge)) {
// Pip should be minimized
setMinimizedStateInternal(true);
if (mMenuController.isMenuVisible()) {
@@ -563,9 +589,7 @@
mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds);
}
- final PointF vel = mTouchState.getVelocity();
- final float velocity = PointF.length(vel.x, vel.y);
- if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+ if (isFling) {
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
mUpdateScrimListener);
} else {
@@ -585,42 +609,6 @@
};
/**
- * @return whether the gesture ending in {@param vel} is fast enough to be a fling and towards
- * the provided {@param edge} where:
- *
- * 1 = top
- * 2 = left
- * 3 = right
- * 4 = bottom
- */
- private boolean isFlingTowardsEdge(PipTouchState touchState, int edge) {
- final PointF vel = touchState.getVelocity();
- final PointF downPos = touchState.getDownTouchPosition();
- final Rect bounds = mMotionHelper.getBounds();
- final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
- final boolean isFling =
- PointF.length(vel.x, vel.y) > mFlingAnimationUtils.getMinVelocityPxPerSecond();
- if (!isFling) {
- return false;
- }
- switch (edge) {
- case 1: // top
- return !isHorizontal && vel.y < 0
- && downPos.y <= mMovementBounds.top + bounds.height();
- case 2: // left
- return isHorizontal && vel.x < 0
- && downPos.x <= mMovementBounds.left + bounds.width();
- case 3: // right
- return isHorizontal && vel.x > 0
- && downPos.x >= mMovementBounds.right;
- case 4: // bottom
- return !isHorizontal && vel.y > 0
- && downPos.y >= mMovementBounds.bottom;
- }
- return false;
- }
-
- /**
* Updates the current movement bounds based on whether the menu is currently visible.
*/
private void updateMovementBounds(boolean isExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 1709718..9efe224 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -14,6 +14,8 @@
package com.android.systemui.qs;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
+
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
@@ -197,7 +199,7 @@
mDetailContent.removeAllViews();
mDetailContent.addView(detailView);
mDetailViews.put(viewCacheIndex, detailView);
- MetricsLogger.visible(mContext, adapter.getMetricsCategory());
+ Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory());
announceForAccessibility(mContext.getString(
R.string.accessibility_quick_settings_detail,
adapter.getTitle()));
@@ -206,7 +208,7 @@
setVisibility(View.VISIBLE);
} else {
if (mDetailAdapter != null) {
- MetricsLogger.hidden(mContext, mDetailAdapter.getMetricsCategory());
+ Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory());
}
mClosingDetail = true;
mDetailAdapter = null;
@@ -238,8 +240,12 @@
protected void setupDetailFooter(DetailAdapter adapter) {
final Intent settingsIntent = adapter.getSettingsIntent();
mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
- mDetailSettingsButton.setOnClickListener(v -> Dependency.get(ActivityStarter.class)
- .postStartActivityDismissingKeyguard(settingsIntent, 0));
+ mDetailSettingsButton.setOnClickListener(v -> {
+ Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS,
+ mDetailAdapter.getMetricsCategory());
+ Dependency.get(ActivityStarter.class)
+ .postStartActivityDismissingKeyguard(settingsIntent, 0);
+ });
}
protected void setupDetailHeader(final DetailAdapter adapter) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 2202b58..a84138d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE;
+
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
@@ -358,6 +360,8 @@
startSettingsActivity();
}
} else if (v == mDateTimeGroup) {
+ Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE,
+ mNextAlarm != null);
if (mNextAlarm != null) {
PendingIntent showIntent = mNextAlarm.getShowIntent();
mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 29d547c..8596b57 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -32,6 +32,8 @@
TileServices getTileServices();
void removeTile(String tileSpec);
+ int indexOf(String tileSpec);
+
interface Callback {
void onTilesChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 8298cbb..2e6116d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -59,6 +59,7 @@
protected final View mBrightnessView;
private final H mHandler = new H();
private final View mPageIndicator;
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private int mPanelPaddingBottom;
private int mBrightnessPaddingTop;
@@ -259,7 +260,7 @@
if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
}
- MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
+ mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded);
if (!mExpanded) {
closeDetail();
} else {
@@ -475,7 +476,7 @@
int newVis = visible ? VISIBLE : INVISIBLE;
setVisibility(newVis);
if (mGridContentVisible != visible) {
- MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis);
+ mMetricsLogger.visibility(MetricsEvent.QS_PANEL, newVis);
}
mGridContentVisible = visible;
}
@@ -483,7 +484,7 @@
private void logTiles() {
for (int i = 0; i < mRecords.size(); i++) {
TileRecord tileRecord = mRecords.get(i);
- MetricsLogger.visible(mContext, tileRecord.tile.getMetricsCategory());
+ mMetricsLogger.visible(tileRecord.tile.getMetricsCategory());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 0ca115e..9330541 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -157,6 +157,10 @@
return mServices;
}
+ public int indexOf(String spec) {
+ return mTileSpecs.indexOf(spec);
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 6f35017..b5c1bd9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -22,6 +22,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -155,6 +156,11 @@
return mComponent;
}
+ @Override
+ protected LogMaker populate(LogMaker logMaker) {
+ return super.populate(logMaker).setComponentName(mComponent);
+ }
+
public Tile getQsTile() {
return mTile;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 948954c2..1aa51b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,12 +14,19 @@
package com.android.systemui.qs.tileimpl;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -29,7 +36,6 @@
import android.util.SparseArray;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
@@ -58,6 +64,7 @@
protected final H mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
private final ArraySet<Object> mListeners = new ArraySet<>();
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
protected TState mState = newTileState();
@@ -76,7 +83,7 @@
/**
* Declare the category of this tile.
*
- * Categories are defined in {@link com.android.internal.logging.MetricsProto.MetricsEvent}
+ * Categories are defined in {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}
* by editing frameworks/base/proto/src/metrics_constants.proto.
*/
abstract public int getMetricsCategory();
@@ -152,17 +159,28 @@
}
public void click() {
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)));
mHandler.sendEmptyMessage(H.CLICK);
}
public void secondaryClick() {
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)));
mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
}
public void longClick() {
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
mHandler.sendEmptyMessage(H.LONG_CLICK);
}
+ protected LogMaker populate(LogMaker logMaker) {
+ if (mState instanceof BooleanState) {
+ logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
+ }
+ return logMaker.setSubtype(getMetricsCategory())
+ .addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
+ }
+
public void showDetail(boolean show) {
mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
}
@@ -224,7 +242,6 @@
}
protected void handleLongClick() {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec());
Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
getLongClickIntent(), 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index ed6e6ef..4e4de15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -83,7 +83,6 @@
protected void handleClick() {
// Secondary clicks are header clicks, just toggle.
final boolean isEnabled = (Boolean)mState.value;
- MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setBluetoothEnabled(!isEnabled);
}
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 a1d3d26..22b6a63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -108,13 +108,11 @@
protected void handleClick() {
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- MetricsLogger.action(mContext, getMetricsCategory());
showDetail(true);
mHost.openPanels();
});
return;
}
- MetricsLogger.action(mContext, getMetricsCategory());
showDetail(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 4351b2c..04be7de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -98,7 +98,6 @@
@Override
protected void handleSecondaryClick() {
- MetricsLogger.action(mContext, getMetricsCategory());
if (mDataController.isMobileDataSupported()) {
showDetail(true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index e33b680..5b374b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -84,7 +84,6 @@
@Override
protected void handleClick() {
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 7a25140..b796451 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -87,7 +87,6 @@
private void toggleDataSaver() {
mState.value = !mDataSaverController.isDataSaverEnabled();
- MetricsLogger.action(mContext, getMetricsCategory(), mState.value);
mDataSaverController.setDataSaverEnabled(mState.value);
refreshState(mState.value);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index f35de68..3c2e897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -146,7 +146,6 @@
Toast.LENGTH_LONG).show();
return;
}
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
showDetail(true);
int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
mController.setZen(zen, null, TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 7b0fd73..6d2aa90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -87,7 +87,6 @@
if (ActivityManager.isUserAMonkey()) {
return;
}
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
boolean newState = !mState.value;
refreshState(newState);
mFlashlightController.setFlashlight(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 6662937..5c3f65c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -106,7 +106,6 @@
if (!isEnabled && mAirplaneMode.getValue() != 0) {
return;
}
- MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setHotspotEnabled(!isEnabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index c953363..00cfbfa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -92,7 +92,6 @@
@Override
protected void handleClick() {
- MetricsLogger.action(mContext, getMetricsCategory(), mIntentPackage);
sendIntent("click", mOnClick, mOnClickUri);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index b5c02cb..b11b15a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -81,13 +81,11 @@
Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
final boolean wasEnabled = mState.value;
mHost.openPanels();
- MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
});
return;
}
final boolean wasEnabled = mState.value;
- MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 3299339..d147b69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -85,7 +85,6 @@
@Override
protected void handleClick() {
if (mAdapter == null) return;
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (!mAdapter.isEnabled()) {
mAdapter.enable();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 8b47216..8aa1e43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -54,7 +54,6 @@
@Override
protected void handleClick() {
final boolean activated = !mState.value;
- MetricsLogger.action(mContext, getMetricsCategory(), activated);
mController.setActivated(activated);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 130304f..fb937bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -79,7 +79,6 @@
@Override
protected void handleClick() {
if (mController == null) return;
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
final boolean newState = !mState.value;
mController.setRotationLocked(!newState);
refreshState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index fde2e04..79b4c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -114,7 +114,6 @@
protected void handleClick() {
// Secondary clicks are header clicks, just toggle.
mState.copyTo(mStateBeforeClick);
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mController.setWifiEnabled(!mState.value);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 5086091..6c89241 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -68,7 +68,6 @@
@Override
public void handleClick() {
- MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mProfileController.setWorkModeEnabled(!mState.value);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index b5f56c3..4d99a46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -22,6 +22,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
@@ -33,7 +34,7 @@
private ArrayMap<Integer, Integer> mLegacyMap;
private LogMaker mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
.setType(MetricsEvent.TYPE_ACTION);
- private MetricsLogger mMetricsLogger = new MetricsLogger();
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
public LockscreenGestureLogger() {
mLegacyMap = new ArrayMap<>(EventLogConstants.METRICS_GESTURE_TYPE_MAP.length);
@@ -58,9 +59,4 @@
}
return value;
}
-
- @VisibleForTesting
- void setMetricsLogger(MetricsLogger metricsLogger) {
- mMetricsLogger = metricsLogger;
- }
}
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 b82b113..bfe55bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -484,7 +484,7 @@
private ScreenPinningRequest mScreenPinningRequest;
- MetricsLogger mMetricsLogger = new MetricsLogger();
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
// ensure quick settings is disabled until the current user makes it through the setup wizard
private boolean mUserSetup = false;
@@ -748,12 +748,6 @@
private NavigationBarFragment mNavigationBar;
private View mNavigationBarView;
- @VisibleForTesting
- void setMetricsLogger(MetricsLogger metricsLogger) {
- mMetricsLogger = metricsLogger;
- mLockscreenGestureLogger.setMetricsLogger(metricsLogger);
- }
-
@Override
public void start() {
mNetworkController = Dependency.get(NetworkController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
new file mode 100644
index 0000000..c67cccc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.ViewUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.DetailAdapter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class QSDetailTest extends SysuiTestCase {
+
+ private MetricsLogger mMetricsLogger;
+ private QSDetail mQsDetail;
+ private QSPanel mQsPanel;
+ private QuickStatusBarHeader mQuickHeader;
+ private ActivityStarter mActivityStarter;
+ private DetailAdapter mMockDetailAdapter;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setup() throws Exception {
+ mTestableLooper = TestableLooper.get(this);
+ mTestableLooper.runWithLooper(() -> {
+ mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+ mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null);
+ mQsPanel = mock(QSPanel.class);
+ mQuickHeader = mock(QuickStatusBarHeader.class);
+ mQsDetail.setQsPanel(mQsPanel, mQuickHeader);
+
+ mMockDetailAdapter = mock(DetailAdapter.class);
+ when(mMockDetailAdapter.createDetailView(any(), any(), any()))
+ .thenReturn(mock(View.class));
+ });
+ }
+
+ @Test
+ public void testShowDetail_Metrics() {
+ ViewUtils.attachView(mQsDetail);
+ mTestableLooper.processAllMessages();
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ verify(mMetricsLogger).visible(eq(mMockDetailAdapter.getMetricsCategory()));
+ mQsDetail.handleShowingDetail(null, 0, 0, false);
+ verify(mMetricsLogger).hidden(eq(mMockDetailAdapter.getMetricsCategory()));
+
+ ViewUtils.detachView(mQsDetail);
+ mTestableLooper.processAllMessages();
+ }
+
+ @Test
+ public void testMoreSettingsButton() {
+ ViewUtils.attachView(mQsDetail);
+ mTestableLooper.processAllMessages();
+
+ mQsDetail.handleShowingDetail(mMockDetailAdapter, 0, 0, false);
+ mQsDetail.findViewById(android.R.id.button2).performClick();
+
+ int metricsCategory = mMockDetailAdapter.getMetricsCategory();
+ verify(mMetricsLogger).action(eq(ACTION_QS_MORE_SETTINGS), eq(metricsCategory));
+
+ verify(mActivityStarter).postStartActivityDismissingKeyguard(any(), anyInt());
+
+ ViewUtils.detachView(mQsDetail);
+ mTestableLooper.processAllMessages();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index deb31da..d77ed3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -19,6 +19,7 @@
import android.os.Looper;
+import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.CarrierText;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -44,12 +45,15 @@
@RunWithLooper(setAsMainLooper = true)
public class QSFragmentTest extends SysuiBaseFragmentTest {
+ private MetricsLogger mMockMetricsLogger;
+
public QSFragmentTest() {
super(QSFragment.class);
}
@Before
public void addLeakCheckDependencies() {
+ mMockMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
new LayoutInflaterBuilder(mContext)
.replace("com.android.systemui.statusbar.policy.SplitClockView",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
new file mode 100644
index 0000000..4979684
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.customize.QSCustomizer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class QSPanelTest extends SysuiTestCase {
+
+ private MetricsLogger mMetricsLogger;
+ private QSPanel mQsPanel;
+ private QSTileHost mHost;
+ private QSCustomizer mCustomizer;
+
+ @Before
+ public void setup() throws Exception {
+ TestableLooper.get(this).runWithLooper(() -> {
+ mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mQsPanel = new QSPanel(mContext, null);
+ mHost = mock(QSTileHost.class);
+ when(mHost.getTiles()).thenReturn(Collections.emptyList());
+ mCustomizer = mock(QSCustomizer.class);
+ mQsPanel.setHost(mHost, mCustomizer);
+ });
+ }
+
+ @Test
+ public void testSetExpanded_Metrics() {
+ mQsPanel.setExpanded(true);
+ verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true));
+ mQsPanel.setExpanded(false);
+ verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(false));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
new file mode 100644
index 0000000..9ed9d28c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs.tileimpl;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.metrics.LogMaker;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QSTileHost;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class QSTileImplTest extends SysuiTestCase {
+
+ public static final int POSITION = 14;
+ private TestableLooper mTestableLooper;
+ private TileImpl mTile;
+ private QSTileHost mHost;
+ private MetricsLogger mMetricsLogger;
+
+ @Before
+ public void setup() throws Exception {
+ String spec = "spec";
+ mTestableLooper = TestableLooper.get(this);
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mHost = mock(QSTileHost.class);
+ when(mHost.indexOf(spec)).thenReturn(POSITION);
+ mTestableLooper.runWithLooper(() -> {
+ mTile = new TileImpl(mHost);
+ mTile.setTileSpec(spec);
+ });
+ }
+
+ @Test
+ public void testClick_Metrics() {
+ mTile.click();
+ verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_CLICK)));
+ }
+
+ @Test
+ public void testSecondaryClick_Metrics() {
+ mTile.secondaryClick();
+ verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
+ }
+
+ @Test
+ public void testLongClick_Metrics() {
+ mTile.longClick();
+ verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS)));
+ }
+
+ @Test
+ public void testPopulate() {
+ LogMaker maker = mock(LogMaker.class);
+ when(maker.setSubtype(anyInt())).thenReturn(maker);
+ mTile.getState().value = true;
+ mTile.populate(maker);
+ verify(maker).addTaggedData(eq(FIELD_QS_VALUE), eq(1));
+ verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION));
+ }
+
+ private class TileLogMatcher implements ArgumentMatcher<LogMaker> {
+
+ private final int mCategory;
+ public String mInvalid;
+
+ public TileLogMatcher(int category) {
+ mCategory = category;
+ }
+
+ @Override
+ public boolean matches(LogMaker arg) {
+ if (arg.getCategory() != mCategory) {
+ mInvalid = "Expected category " + mCategory + " but was " + arg.getCategory();
+ return false;
+ }
+ if (arg.getType() != TYPE_ACTION) {
+ mInvalid = "Expected type " + TYPE_ACTION + " but was " + arg.getType();
+ return false;
+ }
+ if (arg.getSubtype() != mTile.getMetricsCategory()) {
+ mInvalid = "Expected subtype " + mTile.getMetricsCategory() + " but was "
+ + arg.getSubtype();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return mInvalid;
+ }
+ }
+
+ private static class TileImpl extends QSTileImpl<QSTile.BooleanState> {
+ protected TileImpl(QSHost host) {
+ super(host);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ protected void handleClick() {
+
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return 42;
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return null;
+ }
+
+ @Override
+ protected void setListening(boolean listening) {
+
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return null;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f48af75..bf6b394 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -62,9 +62,9 @@
mKeyguardIndicationController = mock(KeyguardIndicationController.class);
mStackScroller = mock(NotificationStackScrollLayout.class);
mMetricsLogger = new FakeMetricsLogger();
+ mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
mKeyguardIndicationController, mStackScroller);
- mStatusBar.setMetricsLogger(mMetricsLogger);
doAnswer(invocation -> {
OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 783aae7..da441f5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3656,7 +3656,7 @@
ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870;
// The name of the activity being launched in an app transition event.
- APP_TRANSITION_ACTIVITY_NAME = 871;
+ FIELD_CLASS_NAME = 871;
// ACTION: Settings > App detail > Uninstall
ACTION_SETTINGS_UNINSTALL_APP = 872;
@@ -3874,6 +3874,24 @@
// OPEN: Settings -> System -> Reset options
RESET_DASHBOARD = 924;
+ // ACTION: QS -> Tile clicked
+ ACTION_QS_CLICK = 925;
+
+ // ACTION: QS -> Secondary click
+ ACTION_QS_SECONDARY_CLICK = 926;
+
+ // FIELD: Position info in QS clicks
+ FIELD_QS_POSITION = 927;
+
+ // FIELD: The value of a QS tile when clicked (if applicable)
+ FIELD_QS_VALUE = 928;
+
+ // ACTION: QS -> Detail panel -> more settings
+ ACTION_QS_MORE_SETTINGS = 929;
+
+ // ACTION: QS -> Click date
+ ACTION_QS_DATE = 930;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 04a09fe..5edfb06 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -10,8 +10,8 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_ACTIVITY_NAME;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
@@ -313,7 +313,7 @@
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.launchedActivity.packageName);
builder.setType(type);
- builder.addTaggedData(APP_TRANSITION_ACTIVITY_NAME, info.launchedActivity.info.name);
+ builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
if (info.launchedActivity.launchedFromPackage != null) {
builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
info.launchedActivity.launchedFromPackage);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9a4f804..28a4e1a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -759,6 +759,12 @@
}
}
+ final void removeActivitiesFromLRUListLocked(TaskRecord task) {
+ for (ActivityRecord r : task.mActivities) {
+ mLRUActivities.remove(r);
+ }
+ }
+
final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -4947,6 +4953,7 @@
}
}
mTaskHistory.remove(task);
+ removeActivitiesFromLRUListLocked(task);
updateTaskMovement(task, true);
if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
@@ -5114,6 +5121,7 @@
// Apps may depend on onResume()/onPause() being called in pairs.
if (setResume) {
mResumedActivity = r;
+ updateLRUListLocked(r);
}
// If the activity was previously pausing, then ensure we transfer that as well
if (setPause) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 27b8e91..8559dca 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3555,8 +3555,16 @@
stackHeader.append(" mFullscreen=" + stack.mFullscreen);
stackHeader.append("\n");
stackHeader.append(" mBounds=" + stack.mBounds);
- printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
- needSep, stackHeader.toString());
+
+ final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
+ dumpClient, dumpPackage, needSep, stackHeader.toString());
+ printed |= printedStackHeader;
+ if (!printedStackHeader) {
+ // Ensure we always dump the stack header even if there are no activities
+ pw.println();
+ pw.println(stackHeader);
+ }
+
printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false,
!dumpAll, false, dumpPackage, true,
" Running activities (most recent first):", null);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f0732dd..da49eb3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -317,7 +317,7 @@
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
- // property so that it is in sync. We can't do this in
+ // property so that it is in sync. We can | xq oqi't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
index 9356dac..7790698 100644
--- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
+++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
@@ -20,6 +20,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import android.Manifest;
+import android.annotation.CheckResult;
import android.annotation.Nullable;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
@@ -36,8 +37,11 @@
import android.net.NetworkPolicyManager;
import android.os.Binder;
import android.os.Environment;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IDeviceIdleController;
+import android.os.IInterface;
+import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -68,11 +72,13 @@
import java.util.function.Function;
//TODO move to own package!
-//TODO un/linkToDeath & onBinderDied - unbind
//TODO onStop schedule unbind in 5 seconds
-//TODO Prune association on app uninstall
+//TODO make sure APIs are only callable from currently focused app
+//TODO schedule stopScan on activity destroy(except if configuration change)
+//TODO on associate called again after configuration change -> replace old callback with new
+//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
/** @hide */
-public class CompanionDeviceManagerService extends SystemService {
+public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
@@ -90,6 +96,8 @@
private final CompanionDeviceManagerImpl mImpl;
private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
private IDeviceIdleController mIdleController;
+ private IFindDeviceCallback mFindDeviceCallback;
+ private ServiceConnection mServiceConnection;
public CompanionDeviceManagerService(Context context) {
super(context);
@@ -125,7 +133,51 @@
publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
}
+ @Override
+ public void binderDied() {
+ Handler.getMain().post(this::handleBinderDied);
+ }
+
+ private void handleBinderDied() {
+ mServiceConnection = unbind(mServiceConnection);
+ mFindDeviceCallback = unlinkToDeath(mFindDeviceCallback, this, 0);
+ }
+
+ /**
+ * Usage: {@code a = unlinkToDeath(a, deathRecipient, flags); }
+ */
+ @Nullable
+ @CheckResult
+ private static <T extends IInterface> T unlinkToDeath(T iinterface,
+ IBinder.DeathRecipient deathRecipient, int flags) {
+ if (iinterface != null) {
+ iinterface.asBinder().unlinkToDeath(deathRecipient, flags);
+ }
+ return null;
+ }
+
+ @Nullable
+ @CheckResult
+ private ServiceConnection unbind(@Nullable ServiceConnection conn) {
+ if (conn != null) {
+ getContext().unbindService(conn);
+ }
+ return null;
+ }
+
class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (Throwable e) {
+ Slog.e(LOG_TAG, "Error during IPC", e);
+ throw ExceptionUtils.propagate(e, RemoteException.class);
+ }
+ }
+
@Override
public void associate(
AssociationRequest request,
@@ -135,14 +187,14 @@
Slog.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback
+ ", callingPackage = " + callingPackage + ")");
}
- checkNotNull(request);
- checkNotNull(callback);
+ checkNotNull(request, "Request cannot be null");
+ checkNotNull(callback, "Callback cannot be null");
final long callingIdentity = Binder.clearCallingIdentity();
try {
//TODO bindServiceAsUser
getContext().bindService(
new Intent().setComponent(SERVICE_TO_BIND_TO),
- getServiceConnection(request, callback, callingPackage),
+ createServiceConnection(request, callback, callingPackage),
Context.BIND_AUTO_CREATE);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
@@ -168,11 +220,11 @@
return UserHandle.getUserId(Binder.getCallingUid());
}
- private ServiceConnection getServiceConnection(
+ private ServiceConnection createServiceConnection(
final AssociationRequest request,
final IFindDeviceCallback findDeviceCallback,
final String callingPackage) {
- return new ServiceConnection() {
+ mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) {
@@ -180,6 +232,14 @@
"onServiceConnected(name = " + name + ", service = "
+ service + ")");
}
+ mFindDeviceCallback = findDeviceCallback;
+ try {
+ mFindDeviceCallback.asBinder().linkToDeath(
+ CompanionDeviceManagerService.this, 0);
+ } catch (RemoteException e) {
+ handleBinderDied();
+ return;
+ }
try {
ICompanionDeviceDiscoveryService.Stub
.asInterface(service)
@@ -198,6 +258,7 @@
if (DEBUG) Slog.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")");
}
};
+ return mServiceConnection;
}
private ICompanionDeviceDiscoveryServiceCallback.Stub getServiceCallback() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 1b28db7..e55e073 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -20,6 +20,7 @@
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.os.Build;
+import android.os.SystemProperties;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TimeUtils;
@@ -56,6 +57,9 @@
private static final boolean DEBUG = UsageStatsService.DEBUG;
private static final String BAK_SUFFIX = ".bak";
private static final String CHECKED_IN_SUFFIX = UsageStatsXml.CHECKED_IN_SUFFIX;
+ private static final String RETENTION_LEN_KEY = "ro.usagestats.chooser.retention";
+ private static final int SELECTION_LOG_RETENTION_LEN =
+ SystemProperties.getInt(RETENTION_LEN_KEY, 14);
private final Object mLock = new Object();
private final File[] mIntervalDirs;
@@ -504,7 +508,7 @@
mCal.getTimeInMillis());
mCal.setTimeInMillis(currentTimeMillis);
- mCal.addDays(-14);
+ mCal.addDays(-SELECTION_LOG_RETENTION_LEN);
for (int i = 0; i < mIntervalDirs.length; ++i) {
pruneChooserCountsOlderThan(mIntervalDirs[i], mCal.getTimeInMillis());
}