diff options
102 files changed, 1772 insertions, 2235 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java index a27e16a46a04..279681bc0d15 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/MessageDigestPerfTest.java @@ -51,7 +51,7 @@ public class MessageDigestPerfTest { @Parameterized.Parameter(0) public Algorithm mAlgorithm; - public String mProvider = "AndroidSSL"; + public String mProvider = "AndroidOpenSSL"; private static final int DATA_SIZE = 8192; private static final byte[] DATA = new byte[DATA_SIZE]; diff --git a/api/Android.bp b/api/Android.bp index 7729a7f75d53..e9930e3a3b5b 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -194,6 +194,37 @@ genrule { "$(location :frameworks-base-api-module-lib-current.txt)", } +// This produces the same annotations.zip as framework-doc-stubs, but by using +// outputs from individual modules instead of all the source code. +genrule_defaults { + name: "sdk-annotations-defaults", + out: ["annotations.zip"], + tools: [ + "merge_annotation_zips", + "soong_zip", + ], + cmd: "$(location merge_annotation_zips) $(genDir)/out $(in) && " + + "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out", +} + +genrule { + name: "sdk-annotations.zip", + defaults: ["sdk-annotations-defaults"], + srcs: [ + ":android-non-updatable-doc-stubs{.annotations.zip}", + ":all-modules-public-annotations", + ], +} + +genrule { + name: "sdk-annotations-system.zip", + defaults: ["sdk-annotations-defaults"], + srcs: [ + ":android-non-updatable-doc-stubs-system{.annotations.zip}", + ":all-modules-system-annotations", + ], +} + genrule { name: "combined-removed-dex", visibility: [ diff --git a/api/api.go b/api/api.go index ca0fc28cdb9d..f15804156bdf 100644 --- a/api/api.go +++ b/api/api.go @@ -148,17 +148,18 @@ func createMergedStubsSrcjar(ctx android.LoadHookContext, modules []string) { ctx.CreateModule(genrule.GenRuleFactory, &props) } -// This produces the same annotations.zip as framework-doc-stubs, but by using -// outputs from individual modules instead of all the source code. -func createMergedAnnotations(ctx android.LoadHookContext, modules []string) { - props := genruleProps{} - props.Name = proptools.StringPtr("sdk-annotations.zip") - props.Tools = []string{"merge_annotation_zips", "soong_zip"} - props.Out = []string{"annotations.zip"} - props.Cmd = proptools.StringPtr("$(location merge_annotation_zips) $(genDir)/out $(in) && " + - "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out") - props.Srcs = append([]string{":android-non-updatable-doc-stubs{.annotations.zip}"}, createSrcs(modules, "{.public.annotations.zip}")...) - ctx.CreateModule(genrule.GenRuleFactory, &props) +func createMergedPublicAnnotationsFilegroup(ctx android.LoadHookContext, modules []string) { + props := fgProps{} + props.Name = proptools.StringPtr("all-modules-public-annotations") + props.Srcs = createSrcs(modules, "{.public.annotations.zip}") + ctx.CreateModule(android.FileGroupFactory, &props) +} + +func createMergedSystemAnnotationsFilegroup(ctx android.LoadHookContext, modules []string) { + props := fgProps{} + props.Name = proptools.StringPtr("all-modules-system-annotations") + props.Srcs = createSrcs(modules, "{.system.annotations.zip}") + ctx.CreateModule(android.FileGroupFactory, &props) } func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { @@ -291,7 +292,8 @@ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { createMergedFrameworkModuleLibStubs(ctx, bootclasspath) createMergedFrameworkImpl(ctx, bootclasspath) - createMergedAnnotations(ctx, bootclasspath) + createMergedPublicAnnotationsFilegroup(ctx, bootclasspath) + createMergedSystemAnnotationsFilegroup(ctx, bootclasspath) createFilteredApiVersions(ctx, bootclasspath) diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 1b2d905aec0a..073d987f5dad 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -234,7 +234,11 @@ Status Idmap2Service::createFabricatedOverlay( } for (const auto& res : overlay.entries) { - builder.SetResourceValue(res.resourceName, res.dataType, res.data); + if (res.dataType == Res_value::TYPE_STRING) { + builder.SetResourceValue(res.resourceName, res.dataType, res.stringData.value()); + } else { + builder.SetResourceValue(res.resourceName, res.dataType, res.data); + } } // Generate the file path of the fabricated overlay and ensure it does not collide with an diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl index 6c2af274ae32..a6824da8c424 100644 --- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl +++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl @@ -23,4 +23,5 @@ parcelable FabricatedOverlayInternalEntry { @utf8InCpp String resourceName; int dataType; int data; + @nullable @utf8InCpp String stringData; }
\ No newline at end of file diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h index 375671881e5f..65916d7ebf49 100644 --- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h +++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h @@ -41,6 +41,9 @@ struct FabricatedOverlay { Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type, uint32_t data_value); + Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type, + const std::string& data_string_value); + WARN_UNUSED Result<FabricatedOverlay> Build(); private: @@ -48,6 +51,7 @@ struct FabricatedOverlay { std::string resource_name; DataType data_type; DataValue data_value; + std::string data_string_value; }; std::string package_name_; diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h index a0202dfee473..414aa064ada7 100644 --- a/cmds/idmap2/include/idmap2/ResourceUtils.h +++ b/cmds/idmap2/include/idmap2/ResourceUtils.h @@ -40,6 +40,7 @@ using DataValue = uint32_t; // Res_value::data struct TargetValue { DataType data_type; DataValue data_value; + std::string data_string_value; }; namespace utils { diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp index 8352dbb7b619..4d49674efce3 100644 --- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp +++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp @@ -65,7 +65,13 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( const std::string& resource_name, uint8_t data_type, uint32_t data_value) { - entries_.emplace_back(Entry{resource_name, data_type, data_value}); + entries_.emplace_back(Entry{resource_name, data_type, data_value, ""}); + return *this; +} + +FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue( + const std::string& resource_name, uint8_t data_type, const std::string& data_string_value) { + entries_.emplace_back(Entry{resource_name, data_type, 0, data_string_value}); return *this; } @@ -111,7 +117,8 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() { entry = type->second.insert(std::make_pair(entry_name.to_string(), TargetValue())).first; } - entry->second = TargetValue{res_entry.data_type, res_entry.data_value}; + entry->second = TargetValue{ + res_entry.data_type, res_entry.data_value, res_entry.data_string_value}; } pb::FabricatedOverlay overlay_pb; diff --git a/core/api/current.txt b/core/api/current.txt index b4f75d4fb193..7eb55eda6be8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18154,7 +18154,7 @@ package android.hardware.camera2.params { } public final class Capability { - ctor public Capability(int, int, int, float, float); + ctor public Capability(int, @NonNull android.util.Size, @NonNull android.util.Range<java.lang.Float>); method @NonNull public android.util.Size getMaxStreamingSize(); method public int getMode(); method @NonNull public android.util.Range<java.lang.Float> getZoomRatioRange(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index cb64173b7809..4130f8074224 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -7563,10 +7563,15 @@ public class AppOpsManager { @SystemApi @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops) { - final int opCount = ops.length; - final int[] opCodes = new int[opCount]; - for (int i = 0; i < opCount; i++) { - opCodes[i] = sOpStrToOp.get(ops[i]); + final int[] opCodes; + if (ops != null) { + final int opCount = ops.length; + opCodes = new int[opCount]; + for (int i = 0; i < opCount; i++) { + opCodes[i] = sOpStrToOp.get(ops[i]); + } + } else { + opCodes = null; } final List<AppOpsManager.PackageOps> result = getPackagesForOps(opCodes); return (result != null) ? result : Collections.emptyList(); diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 14c671f32c21..b6b860d42ccb 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -38,15 +38,22 @@ import android.content.IntentSender; import android.content.pm.PackageManager; import android.net.MacAddress; import android.os.Handler; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.ExceptionUtils; import android.util.Log; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.CollectionUtils; +import libcore.io.IoUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -273,6 +280,9 @@ public final class CompanionDeviceManager { @GuardedBy("mListeners") private final ArrayList<OnAssociationsChangedListenerProxy> mListeners = new ArrayList<>(); + @GuardedBy("mTransports") + private final SparseArray<Transport> mTransports = new SparseArray<>(); + /** @hide */ public CompanionDeviceManager( @Nullable ICompanionDeviceManager service, @NonNull Context context) { @@ -800,6 +810,36 @@ public final class CompanionDeviceManager { } } + /** {@hide} */ + public final void attachSystemDataTransport(int associationId, @NonNull InputStream in, + @NonNull OutputStream out) throws DeviceNotAssociatedException { + synchronized (mTransports) { + if (mTransports.contains(associationId)) { + detachSystemDataTransport(associationId); + } + + try { + final Transport transport = new Transport(associationId, in, out); + mTransports.put(associationId, transport); + transport.start(); + } catch (IOException e) { + throw new RuntimeException("Failed to attach transport", e); + } + } + } + + /** {@hide} */ + public final void detachSystemDataTransport(int associationId) + throws DeviceNotAssociatedException { + synchronized (mTransports) { + final Transport transport = mTransports.get(associationId); + if (transport != null) { + mTransports.delete(associationId); + transport.stop(); + } + } + } + /** * Associates given device with given app for the given user directly, without UI prompt. * @@ -1004,4 +1044,93 @@ public final class CompanionDeviceManager { mExecutor.execute(() -> mListener.onAssociationsChanged(associations)); } } + + /** + * Representation of an active system data transport. + * <p> + * Internally uses two threads to shuttle bidirectional data between a + * remote device and a {@code socketpair} that the system is listening to. + * This design ensures that data payloads are transported efficiently + * without adding Binder traffic contention. + */ + private class Transport { + private final int mAssociationId; + private final InputStream mRemoteIn; + private final OutputStream mRemoteOut; + + private InputStream mLocalIn; + private OutputStream mLocalOut; + + private volatile boolean mStopped; + + public Transport(int associationId, InputStream remoteIn, OutputStream remoteOut) { + mAssociationId = associationId; + mRemoteIn = remoteIn; + mRemoteOut = remoteOut; + } + + public void start() throws IOException { + final ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(); + mLocalIn = new ParcelFileDescriptor.AutoCloseInputStream(pair[0]); + mLocalOut = new ParcelFileDescriptor.AutoCloseOutputStream(pair[0]); + + try { + mService.attachSystemDataTransport(mContext.getPackageName(), + mContext.getUserId(), mAssociationId, pair[1]); + } catch (RemoteException e) { + throw new IOException("Failed to configure transport", e); + } + + new Thread(() -> { + try { + copyWithFlushing(mLocalIn, mRemoteOut); + } catch (IOException e) { + if (!mStopped) { + Log.w(LOG_TAG, "Trouble during outgoing transport", e); + stop(); + } + } + }).start(); + new Thread(() -> { + try { + copyWithFlushing(mRemoteIn, mLocalOut); + } catch (IOException e) { + if (!mStopped) { + Log.w(LOG_TAG, "Trouble during incoming transport", e); + stop(); + } + } + }).start(); + } + + public void stop() { + mStopped = true; + + IoUtils.closeQuietly(mRemoteIn); + IoUtils.closeQuietly(mRemoteOut); + IoUtils.closeQuietly(mLocalIn); + IoUtils.closeQuietly(mLocalOut); + + try { + mService.detachSystemDataTransport(mContext.getPackageName(), + mContext.getUserId(), mAssociationId); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Failed to detach transport", e); + } + } + + /** + * Copy all data from the first stream to the second stream, flushing + * after every write to ensure that we quickly deliver all pending data. + */ + private void copyWithFlushing(@NonNull InputStream in, @NonNull OutputStream out) + throws IOException { + byte[] buffer = new byte[8192]; + int c; + while ((c = in.read(buffer)) != -1) { + out.write(buffer, 0, c); + out.flush(); + } + } + } } diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java index 791fc2aaa2cb..83d2713ea114 100644 --- a/core/java/android/companion/CompanionDeviceService.java +++ b/core/java/android/companion/CompanionDeviceService.java @@ -23,11 +23,14 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.Service; +import android.bluetooth.BluetoothSocket; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.util.Log; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Objects; import java.util.concurrent.Executor; @@ -201,6 +204,45 @@ public abstract class CompanionDeviceService extends Service { } /** + * Attach the given bidirectional communication streams to be used for + * transporting system data between associated devices. + * <p> + * The companion service providing these streams is responsible for ensuring + * that all data is transported accurately and in-order between the two + * devices, including any fragmentation and re-assembly when carried over a + * size-limited transport. + * <p> + * As an example, it's valid to provide streams obtained from a + * {@link BluetoothSocket} to this method, since {@link BluetoothSocket} + * meets the API contract described above. + * + * @param associationId id of the associated device + * @param in already connected stream of data incoming from remote + * associated device + * @param out already connected stream of data outgoing to remote associated + * device + * @hide + */ + public final void attachSystemDataTransport(int associationId, @NonNull InputStream in, + @NonNull OutputStream out) throws DeviceNotAssociatedException { + getSystemService(CompanionDeviceManager.class) + .attachSystemDataTransport(associationId, in, out); + } + + /** + * Detach any bidirectional communication streams previously configured + * through {@link #attachSystemDataTransport}. + * + * @param associationId id of the associated device + * @hide + */ + public final void detachSystemDataTransport(int associationId) + throws DeviceNotAssociatedException { + getSystemService(CompanionDeviceManager.class) + .detachSystemDataTransport(associationId); + } + + /** * Called by system whenever a device associated with this app is connected. * * @param associationInfo A record for the companion device. diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 085fd1b4c388..ab7dc09cf459 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -76,4 +76,8 @@ interface ICompanionDeviceManager { int associationId); void startSystemDataTransfer(String packageName, int userId, int associationId); + + void attachSystemDataTransport(String packageName, int userId, int associationId, in ParcelFileDescriptor fd); + + void detachSystemDataTransport(String packageName, int userId, int associationId); } diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java index d62b47b34dcb..5efc1f9f7cca 100644 --- a/core/java/android/content/om/FabricatedOverlay.java +++ b/core/java/android/content/om/FabricatedOverlay.java @@ -88,7 +88,7 @@ public class FabricatedOverlay { } /** - * Sets the value of + * Sets the value of the fabricated overlay * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) @@ -106,6 +106,25 @@ public class FabricatedOverlay { return this; } + /** + * Sets the value of the fabricated overlay + * + * @param resourceName name of the target resource to overlay (in the form + * [package]:type/entry) + * @param dataType the data type of the new value + * @param value the string representing the new value + * + * @see android.util.TypedValue#type + */ + public Builder setResourceValue(@NonNull String resourceName, int dataType, String value) { + final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); + entry.resourceName = resourceName; + entry.dataType = dataType; + entry.stringData = value; + mEntries.add(entry); + return this; + } + /** Builds an immutable fabricated overlay. */ public FabricatedOverlay build() { final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java index 216c9c26424d..db0cac3eb9c7 100644 --- a/core/java/android/database/sqlite/SQLiteConnectionPool.java +++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java @@ -170,8 +170,8 @@ public final class SQLiteConnectionPool implements Closeable { // If timeout is set, setup idle connection handler // In case of MAX_VALUE - idle connections are never closed if (mConfiguration.idleConnectionTimeoutMs != Long.MAX_VALUE) { - setupIdleConnectionHandler(Looper.getMainLooper(), - mConfiguration.idleConnectionTimeoutMs); + setupIdleConnectionHandler( + Looper.getMainLooper(), mConfiguration.idleConnectionTimeoutMs, null); } } @@ -425,7 +425,7 @@ public final class SQLiteConnectionPool implements Closeable { mAvailablePrimaryConnection = connection; } wakeConnectionWaitersLocked(); - } else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize - 1) { + } else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize) { closeConnectionAndLogExceptionsLocked(connection); } else { if (recycleConnectionLocked(connection, status)) { @@ -456,6 +456,11 @@ public final class SQLiteConnectionPool implements Closeable { return true; } + @VisibleForTesting + public boolean hasAnyAvailableNonPrimaryConnection() { + return mAvailableNonPrimaryConnections.size() > 0; + } + /** * Returns true if the session should yield the connection due to * contention over available database connections. @@ -1061,9 +1066,11 @@ public final class SQLiteConnectionPool implements Closeable { * Set up the handler based on the provided looper and timeout. */ @VisibleForTesting - public void setupIdleConnectionHandler(Looper looper, long timeoutMs) { + public void setupIdleConnectionHandler( + Looper looper, long timeoutMs, Runnable onAllConnectionsIdle) { synchronized (mLock) { - mIdleConnectionHandler = new IdleConnectionHandler(looper, timeoutMs); + mIdleConnectionHandler = + new IdleConnectionHandler(looper, timeoutMs, onAllConnectionsIdle); } } @@ -1228,10 +1235,12 @@ public final class SQLiteConnectionPool implements Closeable { private class IdleConnectionHandler extends Handler { private final long mTimeout; + private final Runnable mOnAllConnectionsIdle; - IdleConnectionHandler(Looper looper, long timeout) { + IdleConnectionHandler(Looper looper, long timeout, Runnable onAllConnectionsIdle) { super(looper); mTimeout = timeout; + this.mOnAllConnectionsIdle = onAllConnectionsIdle; } @Override @@ -1247,6 +1256,9 @@ public final class SQLiteConnectionPool implements Closeable { + " after " + mTimeout); } } + if (mOnAllConnectionsIdle != null) { + mOnAllConnectionsIdle.run(); + } } } diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 468e6041eb73..ee12df547291 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -88,8 +88,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -1734,12 +1734,12 @@ public class CameraMetadataNative implements Parcelable { int height = maxSizes[3 * i + 2]; if (mode != CameraMetadata.CONTROL_EXTENDED_SCENE_MODE_DISABLED && j < numExtendedSceneModeZoomRanges) { - capabilities[i] = new Capability(mode, width, height, zoomRanges[2 * j], - zoomRanges[2 * j + 1]); + capabilities[i] = new Capability(mode, new Size(width, height), + new Range<Float>(zoomRanges[2 * j], zoomRanges[2 * j + 1])); j++; } else { - capabilities[i] = new Capability(mode, width, height, modeOffMinZoomRatio, - modeOffMaxZoomRatio); + capabilities[i] = new Capability(mode, new Size(width, height), + new Range<Float>(modeOffMinZoomRatio, modeOffMaxZoomRatio)); } } diff --git a/core/java/android/hardware/camera2/params/Capability.java b/core/java/android/hardware/camera2/params/Capability.java index fd71c82817f5..a015f720241f 100644 --- a/core/java/android/hardware/camera2/params/Capability.java +++ b/core/java/android/hardware/camera2/params/Capability.java @@ -40,10 +40,8 @@ public final class Capability { public static final int COUNT = 3; private final int mMode; - private final int mMaxStreamingWidth; - private final int mMaxStreamingHeight; - private final float mMinZoomRatio; - private final float mMaxZoomRatio; + private final Size mMaxStreamingSize; + private final Range<Float> mZoomRatioRange; /** * Create a new Capability object. @@ -57,29 +55,30 @@ public final class Capability { * objects during normal use of the camera API.</p> * * @param mode supported mode for a camera capability. - * @param maxStreamingWidth The width of the maximum streaming size for this mode - * @param maxStreamingHeight The height of the maximum streaming size for this mode - * @param minZoomRatio the minimum zoom ratio this mode supports - * @param maxZoomRatio the maximum zoom ratio this mode supports + * @param maxStreamingSize The maximum streaming size for this mode + * @param zoomRatioRange the minimum/maximum zoom ratio this mode supports * - * @throws IllegalArgumentException if any of the argument is not valid + * @throws IllegalArgumentException if any of the arguments are not valid */ - public Capability(int mode, int maxStreamingWidth, int maxStreamingHeight, - float minZoomRatio, float maxZoomRatio) { + public Capability(int mode, @NonNull Size maxStreamingSize, + @NonNull Range<Float> zoomRatioRange) { mMode = mode; - mMaxStreamingWidth = checkArgumentNonnegative(maxStreamingWidth, - "maxStreamingWidth must be nonnegative"); - mMaxStreamingHeight = checkArgumentNonnegative(maxStreamingHeight, - "maxStreamingHeight must be nonnegative"); + checkArgumentNonnegative(maxStreamingSize.getWidth(), + "maxStreamingSize.getWidth() must be nonnegative"); + checkArgumentNonnegative(maxStreamingSize.getHeight(), + "maxStreamingSize.getHeight() must be nonnegative"); + mMaxStreamingSize = maxStreamingSize; - if (minZoomRatio > maxZoomRatio) { - throw new IllegalArgumentException("minZoomRatio " + minZoomRatio - + " is greater than maxZoomRatio " + maxZoomRatio); + if (zoomRatioRange.getLower() > zoomRatioRange.getUpper()) { + throw new IllegalArgumentException("zoomRatioRange.getLower() " + + zoomRatioRange.getLower() + " is greater than zoomRatioRange.getUpper() " + + zoomRatioRange.getUpper()); } - mMinZoomRatio = checkArgumentPositive(minZoomRatio, - "minZoomRatio must be positive"); - mMaxZoomRatio = checkArgumentPositive(maxZoomRatio, - "maxZoomRatio must be positive"); + checkArgumentPositive(zoomRatioRange.getLower(), + "zoomRatioRange.getLower() must be positive"); + checkArgumentPositive(zoomRatioRange.getUpper(), + "zoomRatioRange.getUpper() must be positive"); + mZoomRatioRange = zoomRatioRange; } /** @@ -100,7 +99,7 @@ public final class Capability { * @return a new {@link Size} with non-negative width and height */ public @NonNull Size getMaxStreamingSize() { - return new Size(mMaxStreamingWidth, mMaxStreamingHeight); + return mMaxStreamingSize; } /** @@ -109,7 +108,7 @@ public final class Capability { * @return The supported zoom ratio range supported by this capability */ public @NonNull Range<Float> getZoomRatioRange() { - return new Range<Float>(mMinZoomRatio, mMaxZoomRatio); + return mZoomRatioRange; } @@ -132,10 +131,8 @@ public final class Capability { if (obj instanceof Capability) { final Capability other = (Capability) obj; return (mMode == other.mMode - && mMaxStreamingWidth == other.mMaxStreamingWidth - && mMaxStreamingHeight == other.mMaxStreamingHeight - && mMinZoomRatio == other.mMinZoomRatio - && mMaxZoomRatio == other.mMaxZoomRatio); + && mMaxStreamingSize.equals(other.mMaxStreamingSize) + && mZoomRatioRange.equals(other.mZoomRatioRange)); } return false; } @@ -145,8 +142,9 @@ public final class Capability { */ @Override public int hashCode() { - return HashCodeHelpers.hashCode(mMode, mMaxStreamingWidth, mMaxStreamingHeight, - mMinZoomRatio, mMaxZoomRatio); + return HashCodeHelpers.hashCode(mMode, mMaxStreamingSize.getWidth(), + mMaxStreamingSize.getHeight(), mZoomRatioRange.getLower(), + mZoomRatioRange.getUpper()); } /** @@ -158,7 +156,7 @@ public final class Capability { @Override public String toString() { return String.format("(mode:%d, maxStreamingSize:%d x %d, zoomRatio: %f-%f)", - mMode, mMaxStreamingWidth, mMaxStreamingHeight, mMinZoomRatio, - mMaxZoomRatio); + mMode, mMaxStreamingSize.getWidth(), mMaxStreamingSize.getHeight(), + mZoomRatioRange.getLower(), mZoomRatioRange.getUpper()); } } diff --git a/core/java/android/hardware/radio/OWNERS b/core/java/android/hardware/radio/OWNERS index ea4421eae96a..d2bdd643b0a2 100644 --- a/core/java/android/hardware/radio/OWNERS +++ b/core/java/android/hardware/radio/OWNERS @@ -1,2 +1,3 @@ -twasilczyk@google.com -randolphs@google.com +xuweilin@google.com +oscarazu@google.com +keunyoung@google.com diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java index 5bed32cb0438..06930bb32090 100644 --- a/core/java/android/os/VibrationAttributes.java +++ b/core/java/android/os/VibrationAttributes.java @@ -152,6 +152,9 @@ public final class VibrationAttributes implements Parcelable { /** * Flag requesting vibration effect to be played even under limited interruptions. + * + * <p>Only privileged apps can ignore user settings that limit interruptions, and this + * flag will be ignored otherwise. */ public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; diff --git a/core/java/android/window/SizeConfigurationBuckets.java b/core/java/android/window/SizeConfigurationBuckets.java index f474f0a76cc6..998bec0892ae 100644 --- a/core/java/android/window/SizeConfigurationBuckets.java +++ b/core/java/android/window/SizeConfigurationBuckets.java @@ -104,24 +104,15 @@ public final class SizeConfigurationBuckets implements Parcelable { /** * Get the changes between two configurations but don't count changes in sizes if they don't * cross boundaries that are important to the app. - * - * This is a static helper to deal with null `buckets`. When no buckets have been specified, - * this actually filters out all 3 size-configs. This is legacy behavior. */ public static int filterDiff(int diff, @NonNull Configuration oldConfig, @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) { - final boolean nonSizeLayoutFieldsUnchanged = - areNonSizeLayoutFieldsUnchanged(oldConfig.screenLayout, newConfig.screenLayout); if (buckets == null) { - // Only unflip CONFIG_SCREEN_LAYOUT if non-size-related attributes of screen layout do - // not change. - if (nonSizeLayoutFieldsUnchanged) { - return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE - | CONFIG_SCREEN_LAYOUT); - } else { - return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE); - } + return diff; } + + final boolean nonSizeLayoutFieldsUnchanged = + areNonSizeLayoutFieldsUnchanged(oldConfig.screenLayout, newConfig.screenLayout); if ((diff & CONFIG_SCREEN_SIZE) != 0) { final boolean crosses = buckets.crossesHorizontalSizeThreshold(oldConfig.screenWidthDp, newConfig.screenWidthDp) diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index c2b69717bc37..3732ea5abaa5 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -68,13 +68,6 @@ interface IBatteryStats { @EnforcePermission("BATTERY_STATS") List<BatteryUsageStats> getBatteryUsageStats(in List<BatteryUsageStatsQuery> queries); - @UnsupportedAppUsage - @EnforcePermission("BATTERY_STATS") - byte[] getStatistics(); - - @EnforcePermission("BATTERY_STATS") - ParcelFileDescriptor getStatisticsStream(boolean updateAll); - // Return true if we see the battery as currently charging. @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) @RequiresNoPermission diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 4af28ea24361..1520ea5c6831 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -41,7 +41,12 @@ struct { static JNIEnv* getenv(JavaVM* vm) { JNIEnv* env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + auto result = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); + if (result == JNI_EDETACHED) { + if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } else if (result != JNI_OK) { LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); } return env; @@ -60,28 +65,22 @@ public: } ~TransactionHangCallbackWrapper() { - if (mTransactionHangObject) { - getenv()->DeleteGlobalRef(mTransactionHangObject); + if (mTransactionHangObject != nullptr) { + getenv(mVm)->DeleteGlobalRef(mTransactionHangObject); mTransactionHangObject = nullptr; } } void onTransactionHang(bool isGpuHang) { if (mTransactionHangObject) { - getenv()->CallVoidMethod(mTransactionHangObject, - gTransactionHangCallback.onTransactionHang, isGpuHang); + getenv(mVm)->CallVoidMethod(mTransactionHangObject, + gTransactionHangCallback.onTransactionHang, isGpuHang); } } private: JavaVM* mVm; jobject mTransactionHangObject; - - JNIEnv* getenv() { - JNIEnv* env; - mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); - return env; - } }; static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, diff --git a/core/tests/BroadcastRadioTests/OWNERS b/core/tests/BroadcastRadioTests/OWNERS index 3e360e7e992c..d2bdd643b0a2 100644 --- a/core/tests/BroadcastRadioTests/OWNERS +++ b/core/tests/BroadcastRadioTests/OWNERS @@ -1,3 +1,3 @@ -keunyoung@google.com +xuweilin@google.com oscarazu@google.com -twasilczyk@google.com +keunyoung@google.com diff --git a/core/tests/companiontests/src/android/companion/CompanionTestRunner.java b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java index caa2c685accc..3c59e7d716b0 100644 --- a/core/tests/companiontests/src/android/companion/CompanionTestRunner.java +++ b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java @@ -33,6 +33,7 @@ public class CompanionTestRunner extends InstrumentationTestRunner { public TestSuite getAllTests() { TestSuite suite = new InstrumentationTestSuite(this); suite.addTestSuite(BluetoothDeviceFilterUtilsTest.class); + suite.addTestSuite(SystemDataTransportTest.class); return suite; } diff --git a/core/tests/companiontests/src/android/companion/SystemDataTransportTest.java b/core/tests/companiontests/src/android/companion/SystemDataTransportTest.java new file mode 100644 index 000000000000..be04b6c91a8a --- /dev/null +++ b/core/tests/companiontests/src/android/companion/SystemDataTransportTest.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2022 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.companion; + +import android.os.SystemClock; +import android.test.InstrumentationTestCase; +import android.util.Log; + +import com.android.internal.util.HexDump; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Random; + +public class SystemDataTransportTest extends InstrumentationTestCase { + private static final String TAG = "SystemDataTransportTest"; + + private static final int COMMAND_INVALID = 0xF00DCAFE; + private static final int COMMAND_PING_V0 = 0x50490000; + private static final int COMMAND_PONG_V0 = 0x504F0000; + + private CompanionDeviceManager mCdm; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mCdm = getInstrumentation().getTargetContext() + .getSystemService(CompanionDeviceManager.class); + } + + public void testPingHandRolled() { + // NOTE: These packets are explicitly hand-rolled to verify wire format; + // the remainder of the tests are fine using generated packets + + // PING v0 with payload "HELLO WORLD!" + final byte[] input = new byte[] { + 0x50, 0x49, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, + 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x20, 0x57, 0x4F, 0x52, 0x4C, 0x44, 0x21, + }; + // PONG v0 with payload "HELLO WORLD!" + final byte[] expected = new byte[] { + 0x50, 0x4F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, + 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x20, 0x57, 0x4F, 0x52, 0x4C, 0x44, 0x21, + }; + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, in, out); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testPingTrickle() { + final byte[] input = generatePacket(COMMAND_PING_V0, TAG); + final byte[] expected = generatePacket(COMMAND_PONG_V0, TAG); + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, new TrickleInputStream(in), out); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testPingDelay() { + final byte[] input = generatePacket(COMMAND_PING_V0, TAG); + final byte[] expected = generatePacket(COMMAND_PONG_V0, TAG); + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, new DelayingInputStream(in, 1000), + new DelayingOutputStream(out, 1000)); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testPingGiant() { + final byte[] blob = new byte[500_000]; + new Random().nextBytes(blob); + + final byte[] input = generatePacket(COMMAND_PING_V0, blob); + final byte[] expected = generatePacket(COMMAND_PONG_V0, blob); + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, in, out); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testMutiplePingPing() { + final byte[] input = concat(generatePacket(COMMAND_PING_V0, "red"), + generatePacket(COMMAND_PING_V0, "green")); + final byte[] expected = concat(generatePacket(COMMAND_PONG_V0, "red"), + generatePacket(COMMAND_PONG_V0, "green")); + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, in, out); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testMultipleInvalidPing() { + final byte[] input = concat(generatePacket(COMMAND_INVALID, "red"), + generatePacket(COMMAND_PING_V0, "green")); + final byte[] expected = generatePacket(COMMAND_PONG_V0, "green"); + + final ByteArrayInputStream in = new ByteArrayInputStream(input); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, in, out); + + final byte[] actual = waitForByteArray(out, expected.length); + assertEquals(HexDump.toHexString(expected), HexDump.toHexString(actual)); + } + + public void testDoubleAttach() { + // Connect an empty connection that is stalled out + final InputStream in = new EmptyInputStream(); + final OutputStream out = new ByteArrayOutputStream(); + mCdm.attachSystemDataTransport(42, in, out); + SystemClock.sleep(1000); + + // Attach a second transport that has some packets; it should disconnect + // the first transport and start replying on the second one + testPingHandRolled(); + } + + public static byte[] concat(byte[] a, byte[] b) { + return ByteBuffer.allocate(a.length + b.length).put(a).put(b).array(); + } + + public static byte[] generatePacket(int command, String data) { + return generatePacket(command, data.getBytes(StandardCharsets.UTF_8)); + } + + public static byte[] generatePacket(int command, byte[] data) { + return ByteBuffer.allocate(data.length + 8) + .putInt(command).putInt(data.length).put(data).array(); + } + + private static byte[] waitForByteArray(ByteArrayOutputStream out, int size) { + int i = 0; + while (out.size() < size) { + SystemClock.sleep(100); + if (i++ % 10 == 0) { + Log.w(TAG, "Waiting for data..."); + } + if (i > 100) { + fail(); + } + } + return out.toByteArray(); + } + + private static class EmptyInputStream extends InputStream { + @Override + public int read() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + // Instead of hanging indefinitely, wait a bit and claim that + // nothing was read, without hitting EOF + SystemClock.sleep(100); + return 0; + } + } + + private static class DelayingInputStream extends FilterInputStream { + private final long mDelay; + + public DelayingInputStream(InputStream in, long delay) { + super(in); + mDelay = delay; + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + SystemClock.sleep(mDelay); + return super.read(b, off, len); + } + } + + private static class DelayingOutputStream extends FilterOutputStream { + private final long mDelay; + + public DelayingOutputStream(OutputStream out, long delay) { + super(out); + mDelay = delay; + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + SystemClock.sleep(mDelay); + super.write(b, off, len); + } + } + + private static class TrickleInputStream extends FilterInputStream { + public TrickleInputStream(InputStream in) { + super(in); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + return super.read(b, off, 1); + } + } +} diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java index f1d27d4a13ab..2b663bdb7861 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +import java.util.concurrent.CountDownLatch; /** * Tests for {@link SQLiteConnectionPool} @@ -74,7 +75,7 @@ public class SQLiteConnectionPoolTest { Log.i(TAG, "Starting " + thread.getName()); thread.start(); SQLiteConnectionPool pool = SQLiteConnectionPool.open(mTestConf); - pool.setupIdleConnectionHandler(thread.getLooper(), 100); + pool.setupIdleConnectionHandler(thread.getLooper(), 100, null); SQLiteConnection c1 = pool.acquireConnection("pragma user_version", 0, null); assertEquals("First connection should be returned", 0, c1.getConnectionId()); pool.releaseConnection(c1); @@ -89,4 +90,31 @@ public class SQLiteConnectionPoolTest { pool.close(); thread.quit(); } + + @Test + public void testNonprimaryConnectionPoolRecycling() throws InterruptedException { + HandlerThread thread = new HandlerThread("test-close-idle-connections-thread"); + thread.start(); + SQLiteConnectionPool pool = SQLiteConnectionPool.open(mTestConf); + CountDownLatch latch = new CountDownLatch(1); + Runnable onIdleConnectionTimeout = () -> latch.countDown(); + pool.setupIdleConnectionHandler(thread.getLooper(), 1, onIdleConnectionTimeout); + + assertTrue("When the pool was just opened there should only be a primary connection.", + !pool.hasAnyAvailableNonPrimaryConnection()); + SQLiteConnection connection = pool.acquireConnection("pragma user_version", 0, null); + pool.releaseConnection(connection); + assertTrue("First time acquire should will return the primary connection.", + !pool.hasAnyAvailableNonPrimaryConnection()); + + // Wait for primary connection to time out + latch.await(); + + // Now that the primary is closed, acquiring again should open a non primary connection + connection = pool.acquireConnection("pragma user_version", 0, null); + pool.releaseConnection(connection); + assertTrue("There should be an available non primary connection in the pool.", + pool.hasAnyAvailableNonPrimaryConnection()); + pool.close(); + } } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 547144f6ce1a..2ce8fac6d520 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -475,12 +475,6 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" }, - "-1635750891": { - "message": "Received remote change for Display[%d], applied: [%dx%d, rot = %d]", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java" - }, "-1633115609": { "message": "Key dispatch not paused for screen off", "level": "VERBOSE", @@ -1711,6 +1705,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "-417730399": { + "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s", + "level": "DEBUG", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, "-415865166": { "message": "findFocusedWindow: Found new focus @ %s", "level": "VERBOSE", @@ -2137,6 +2137,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "-4263657": { + "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s", + "level": "DEBUG", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, "3593205": { "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b", "level": "VERBOSE", @@ -2599,6 +2605,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "385237117": { + "message": "moveFocusableActivityToTop: already on top and focused, activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "385595355": { "message": "Starting animation on %s: type=%d, anim=%s", "level": "VERBOSE", @@ -3403,6 +3415,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1239439010": { + "message": "moveFocusableActivityToTop: set focused, activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1252594551": { "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d", "level": "WARN", @@ -3877,12 +3895,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "1764619787": { - "message": "Remote change for Display[%d]: timeout reached", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java" - }, "1774661765": { "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.", "level": "WARN", @@ -3991,12 +4003,6 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "1856211951": { - "message": "moveFocusableActivityToTop: already on top, activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "1856783490": { "message": "resumeTopActivity: Restarting %s", "level": "DEBUG", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index bd386b5681d8..37c0c9b01c88 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -942,7 +942,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // Re-set the PIP bounds to none. mPipBoundsState.setBounds(new Rect()); mPipUiEventLoggerLogger.setTaskInfo(null); - mPipMenuController.detach(); + mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0); if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) { mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index c80c14f353d0..05a890fc65ed 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -715,7 +715,7 @@ public class PipTransition extends PipTransitionController { mSurfaceTransactionHelper .crop(finishTransaction, leash, destinationBounds) .round(finishTransaction, leash, true /* applyCornerRadius */); - mPipMenuController.attach(leash); + mTransitions.getMainExecutor().executeDelayed(() -> mPipMenuController.attach(leash), 0); if (taskInfo.pictureInPictureParams != null && taskInfo.pictureInPictureParams.isAutoEnterEnabled() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index a43b6043908b..90a2695bdf90 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -28,9 +28,7 @@ import android.app.TaskInfo; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; @@ -56,7 +54,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final ShellTaskOrganizer mShellTaskOrganizer; protected final PipMenuController mPipMenuController; protected final Transitions mTransitions; - private final Handler mMainHandler; private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>(); protected PipTaskOrganizer mPipOrganizer; @@ -144,7 +141,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipAnimationController = pipAnimationController; mTransitions = transitions; - mMainHandler = new Handler(Looper.getMainLooper()); if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.addHandler(this); } diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index 88ca30ceb8a6..c0261f203604 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -1613,7 +1613,9 @@ public final class TvInteractiveAppManager { mHandler.post(new Runnable() { @Override public void run() { - mSession.getInputSession().requestBroadcastInfo(request); + if (mSession.getInputSession() != null) { + mSession.getInputSession().requestBroadcastInfo(request); + } } }); } @@ -1622,7 +1624,9 @@ public final class TvInteractiveAppManager { mHandler.post(new Runnable() { @Override public void run() { - mSession.getInputSession().removeBroadcastInfo(requestId); + if (mSession.getInputSession() != null) { + mSession.getInputSession().removeBroadcastInfo(requestId); + } } }); } diff --git a/packages/StatementService/OWNERS b/packages/StatementService/OWNERS new file mode 100644 index 000000000000..f0b4ce7bf5b1 --- /dev/null +++ b/packages/StatementService/OWNERS @@ -0,0 +1,2 @@ +include /PACKAGE_MANAGER_OWNERS + diff --git a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt index 0ec8ed3416b8..acb54f6093de 100644 --- a/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt +++ b/packages/StatementService/src/com/android/statementservice/domain/DomainVerificationReceiverV1.kt @@ -67,6 +67,10 @@ class DomainVerificationReceiverV1 : BaseDomainVerificationReceiver() { } } + //clear sp before enqueue unique work since policy is REPLACE + val deContext = context.createDeviceProtectedStorageContext() + val editor = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE)?.edit() + editor?.clear()?.apply() WorkManager.getInstance(context) .beginUniqueWork( "$PACKAGE_WORK_PREFIX_V1$packageName", diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt index 3a3aea9288cd..36c81722b5d9 100644 --- a/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt +++ b/packages/StatementService/src/com/android/statementservice/domain/worker/CollectV1Worker.kt @@ -41,9 +41,7 @@ class CollectV1Worker(appContext: Context, params: WorkerParameters) : Data.Builder() .putInt(VERIFICATION_ID_KEY, verificationId) .apply { - if (DEBUG) { - putString(PACKAGE_NAME_KEY, packageName) - } + putString(PACKAGE_NAME_KEY, packageName) } .build() ) @@ -52,6 +50,18 @@ class CollectV1Worker(appContext: Context, params: WorkerParameters) : override suspend fun doWork() = coroutineScope { if (!AndroidUtils.isReceiverV1Enabled(appContext)) { + //clear sp and commit here + val inputData = params.inputData + val packageName = inputData.getString(PACKAGE_NAME_KEY) + val deContext = appContext.createDeviceProtectedStorageContext() + val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE) + val editor = sp?.edit() + editor?.clear()?.commit() + //delete sp file + val retOfDel = deContext?.deleteSharedPreferences(packageName) + if (DEBUG) { + Log.d(TAG, "delete sp for $packageName return $retOfDel") + } return@coroutineScope Result.success() } @@ -59,7 +69,10 @@ class CollectV1Worker(appContext: Context, params: WorkerParameters) : val verificationId = inputData.getInt(VERIFICATION_ID_KEY, -1) val successfulHosts = mutableListOf<String>() val failedHosts = mutableListOf<String>() - inputData.keyValueMap.entries.forEach { (key, _) -> + val packageName = inputData.getString(PACKAGE_NAME_KEY) + val deContext = appContext.createDeviceProtectedStorageContext() + val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE) + sp?.all?.entries?.forEach { (key, _) -> when { key.startsWith(SingleV1RequestWorker.HOST_SUCCESS_PREFIX) -> successfulHosts += key.removePrefix(SingleV1RequestWorker.HOST_SUCCESS_PREFIX) @@ -69,7 +82,6 @@ class CollectV1Worker(appContext: Context, params: WorkerParameters) : } if (DEBUG) { - val packageName = inputData.getString(PACKAGE_NAME_KEY) Log.d( TAG, "Domain verification v1 request for $packageName: " + "success = $successfulHosts, failed = $failedHosts" @@ -84,6 +96,15 @@ class CollectV1Worker(appContext: Context, params: WorkerParameters) : appContext.packageManager.verifyIntentFilter(verificationId, resultCode, failedHosts) + //clear sp and commit here + val editor = sp?.edit() + editor?.clear()?.commit() + //delete sp file + val retOfDel = deContext?.deleteSharedPreferences(packageName) + if (DEBUG) { + Log.d(TAG, "delete sp for $packageName return $retOfDel") + } + Result.success() } } diff --git a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt index cd8a18218004..7a198cb59ca4 100644 --- a/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt +++ b/packages/StatementService/src/com/android/statementservice/domain/worker/SingleV1RequestWorker.kt @@ -71,16 +71,18 @@ class SingleV1RequestWorker(appContext: Context, params: WorkerParameters) : // Coerce failure results into success so that final collection task gets a chance to run when (result) { - is Result.Success -> Result.success( - Data.Builder() - .putInt("$HOST_SUCCESS_PREFIX$host", status.value) - .build() - ) - is Result.Failure -> Result.success( - Data.Builder() - .putInt("$HOST_FAILURE_PREFIX$host", status.value) - .build() - ) + is Result.Success -> { + val deContext = appContext.createDeviceProtectedStorageContext() + val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE) + sp?.edit()?.putInt("$HOST_SUCCESS_PREFIX$host", status.value)?.apply() + Result.success() + } + is Result.Failure -> { + val deContext = appContext.createDeviceProtectedStorageContext() + val sp = deContext?.getSharedPreferences(packageName, Context.MODE_PRIVATE) + sp?.edit()?.putInt("$HOST_FAILURE_PREFIX$host", status.value)?.apply() + Result.success() + } else -> result } } diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 8f8993f3c8d9..12dfa1042dd7 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -59,26 +59,6 @@ </LinearLayout> - <com.android.systemui.statusbar.KeyguardAffordanceView - android:id="@+id/camera_button" - android:layout_height="@dimen/keyguard_affordance_height" - android:layout_width="@dimen/keyguard_affordance_width" - android:layout_gravity="bottom|end" - android:src="@drawable/ic_camera_alt_24dp" - android:scaleType="center" - android:contentDescription="@string/accessibility_camera_button" - android:tint="?attr/wallpaperTextColor" /> - - <com.android.systemui.statusbar.KeyguardAffordanceView - android:id="@+id/left_button" - android:layout_height="@dimen/keyguard_affordance_height" - android:layout_width="@dimen/keyguard_affordance_width" - android:layout_gravity="bottom|start" - android:src="@*android:drawable/ic_phone" - android:scaleType="center" - android:contentDescription="@string/accessibility_phone_button" - android:tint="?attr/wallpaperTextColor" /> - <ImageView android:id="@+id/wallet_button" android:layout_height="@dimen/keyguard_affordance_fixed_height" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index eff4e00fd07b..771973c36053 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -37,12 +37,6 @@ <item>400</item> </integer-array> - <!-- Show mic or phone affordance on Keyguard --> - <bool name="config_keyguardShowLeftAffordance">false</bool> - - <!-- Show camera affordance on Keyguard --> - <bool name="config_keyguardShowCameraAffordance">false</bool> - <!-- decay duration (from size_max -> size), in ms --> <integer name="navigation_bar_deadzone_hold">333</integer> <integer name="navigation_bar_deadzone_decay">333</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1210b79d3ff5..bde1262116d5 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -671,9 +671,6 @@ <!-- The minimum background radius when swiping to a side for the camera / phone affordances. --> <dimen name="keyguard_affordance_min_background_radius">30dp</dimen> - <!-- The size of the touch targets on the keyguard for the affordances. --> - <dimen name="keyguard_affordance_touch_target_size">120dp</dimen> - <!-- The grow amount for the camera and phone circles when hinting --> <dimen name="hint_grow_amount_sideways">60dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 343ec4f67964..ef672f3a6213 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -313,13 +313,6 @@ <string name="accessibility_scanning_face">Scanning face</string> <!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] --> <string name="accessibility_send_smart_reply">Send</string> - <!-- Content description of the manage notification button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> - <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] --> - <string name="phone_label">open phone</string> - <!-- Click action label for accessibility for the voice assist button. This is not shown on-screen and is an accessibility label for the icon which launches the voice assist from the lock screen.[CHAR LIMIT=NONE] --> - <string name="voice_assist_label">open voice assist</string> - <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] --> - <string name="camera_label">open camera</string> <!-- Button name for "Cancel". [CHAR LIMIT=NONE] --> <string name="cancel">Cancel</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 06247c6c9523..835d6e92a63d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -74,18 +74,27 @@ open class ClockRegistry( open var currentClockId: ClockId get() { - val json = Settings.Secure.getString( - context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE - ) - return gson.fromJson(json, ClockSetting::class.java)?.clockId ?: DEFAULT_CLOCK_ID + return try { + val json = Settings.Secure.getString( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE + ) + gson.fromJson(json, ClockSetting::class.java)?.clockId ?: DEFAULT_CLOCK_ID + } catch (ex: Exception) { + Log.e(TAG, "Failed to parse clock setting", ex) + DEFAULT_CLOCK_ID + } } set(value) { - val json = gson.toJson(ClockSetting(value, System.currentTimeMillis())) - Settings.Secure.putString( - context.contentResolver, - Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json - ) + try { + val json = gson.toJson(ClockSetting(value, System.currentTimeMillis())) + Settings.Secure.putString( + context.contentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json + ) + } catch (ex: Exception) { + Log.e(TAG, "Failed to set clock setting", ex) + } } init { @@ -183,6 +192,6 @@ open class ClockRegistry( private data class ClockSetting( val clockId: ClockId, - val _applied_timestamp: Long + val _applied_timestamp: Long? ) } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index ec4cf2fd8bd4..24b893340ae0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -510,6 +510,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mKeyguardViewManager.isBouncerInTransit() ? BouncerPanelExpansionCalculator .aboutToShowBouncerProgress(fraction) : fraction; updateAlpha(); + updatePauseAuth(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 56bb53b567be..064388fa4514 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -163,7 +163,7 @@ public class Flags { /***************************************/ // 900 - media - public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, false); + public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true); public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false); public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true); public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt index 5df593b64c24..558bcac681d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt @@ -61,7 +61,7 @@ class WiredChargingRippleController @Inject constructor( private val systemClock: SystemClock, private val uiEventLogger: UiEventLogger ) { - private var pluggedIn: Boolean? = null + private var pluggedIn: Boolean = false private val rippleEnabled: Boolean = featureFlags.isEnabled(Flags.CHARGING_RIPPLE) && !SystemProperties.getBoolean("persist.debug.suppress-charging-ripple", false) private var normalizedPortPosX: Float = context.resources.getFloat( @@ -99,15 +99,17 @@ class WiredChargingRippleController @Inject constructor( nowPluggedIn: Boolean, charging: Boolean ) { - // Suppresses the ripple when the state change comes from wireless charging. - if (batteryController.isPluggedInWireless) { + // Suppresses the ripple when the state change comes from wireless charging or + // its dock. + if (batteryController.isPluggedInWireless || + batteryController.isChargingSourceDock) { return } - val wasPluggedIn = pluggedIn - pluggedIn = nowPluggedIn - if ((wasPluggedIn == null || !wasPluggedIn) && nowPluggedIn) { + + if (!pluggedIn && nowPluggedIn) { startRippleWithDebounce() } + pluggedIn = nowPluggedIn } } batteryController.addCallback(batteryStateChangeCallback) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt index 2397005a1a61..52dcf02e3a19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt @@ -17,18 +17,32 @@ package com.android.systemui.statusbar.notification import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogLevel import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.LogLevel.WARNING +import com.android.systemui.log.LogMessage import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.util.Compile import javax.inject.Inject /** Logger for [NotificationEntryManager]. */ class NotificationEntryManagerLogger @Inject constructor( + notifPipelineFlags: NotifPipelineFlags, @NotificationLog private val buffer: LogBuffer ) { + private val devLoggingEnabled by lazy { notifPipelineFlags.isDevLoggingEnabled() } + + private inline fun devLog( + level: LogLevel, + initializer: LogMessage.() -> Unit, + noinline printer: LogMessage.() -> String + ) { + if (Compile.IS_DEBUG && devLoggingEnabled) buffer.log(TAG, level, initializer, printer) + } + fun logNotifAdded(key: String) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = key }, { "NOTIF ADDED $str1" @@ -36,7 +50,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logNotifUpdated(key: String) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = key }, { "NOTIF UPDATED $str1" @@ -44,7 +58,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logInflationAborted(key: String, status: String, reason: String) { - buffer.log(TAG, DEBUG, { + devLog(DEBUG, { str1 = key str2 = status str3 = reason @@ -54,7 +68,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logNotifInflated(key: String, isNew: Boolean) { - buffer.log(TAG, DEBUG, { + devLog(DEBUG, { str1 = key bool1 = isNew }, { @@ -63,7 +77,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logRemovalIntercepted(key: String) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = key }, { "NOTIF REMOVE INTERCEPTED for $str1" @@ -71,7 +85,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logLifetimeExtended(key: String, extenderName: String, status: String) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = key str2 = extenderName str3 = status @@ -81,7 +95,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logNotifRemoved(key: String, removedByUser: Boolean) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = key bool1 = removedByUser }, { @@ -90,7 +104,7 @@ class NotificationEntryManagerLogger @Inject constructor( } fun logFilterAndSort(reason: String) { - buffer.log(TAG, INFO, { + devLog(INFO, { str1 = reason }, { "FILTER AND SORT reason=$str1" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS index 63c37e9584d6..ed80f33be701 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS @@ -9,4 +9,6 @@ juliacr@google.com juliatuttle@google.com lynhan@google.com steell@google.com -yurilin@google.com
\ No newline at end of file +yurilin@google.com + +per-file MediaNotificationProcessor.java = ethibodeau@google.com, asc@google.com diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index aedbd1b56622..0a16fb65b1ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -175,6 +175,10 @@ public final class NotificationEntry extends ListEntry { public boolean mRemoteEditImeAnimatingAway; public boolean mRemoteEditImeVisible; private boolean mExpandAnimationRunning; + /** + * Flag to determine if the entry is blockable by DnD filters + */ + private boolean mBlockable; /** * @param sbn the StatusBarNotification from system server @@ -253,6 +257,7 @@ public final class NotificationEntry extends ListEntry { } mRanking = ranking.withAudiblyAlertedInfo(mRanking); + updateIsBlockable(); } /* @@ -781,15 +786,20 @@ public final class NotificationEntry extends ListEntry { * or is not in an allowList). */ public boolean isBlockable() { + return mBlockable; + } + + private void updateIsBlockable() { if (getChannel() == null) { - return false; + mBlockable = false; + return; } if (getChannel().isImportanceLockedByCriticalDeviceFunction() && !getChannel().isBlockable()) { - return false; + mBlockable = false; + return; } - - return true; + mBlockable = true; } private boolean shouldSuppressVisualEffect(int effect) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt index 3501b44a2c2e..38e3d496a60c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt @@ -19,20 +19,24 @@ package com.android.systemui.statusbar.notification.collection.render import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.statusbar.notification.NotifPipelineFlags import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection import com.android.systemui.util.Compile import javax.inject.Inject class NodeSpecBuilderLogger @Inject constructor( + notifPipelineFlags: NotifPipelineFlags, @NotificationLog private val buffer: LogBuffer ) { + private val devLoggingEnabled by lazy { notifPipelineFlags.isDevLoggingEnabled() } + fun logBuildNodeSpec( oldSections: Set<NotifSection?>, newHeaders: Map<NotifSection?, NodeController?>, newCounts: Map<NotifSection?, Int>, newSectionOrder: List<NotifSection?> ) { - if (!Compile.IS_DEBUG) + if (!(Compile.IS_DEBUG && devLoggingEnabled)) return buffer.log(TAG, LogLevel.DEBUG, { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index 134f24e7e646..27aa4b38e0ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -266,9 +266,14 @@ public class NotificationConversationInfo extends LinearLayout implements snooze.setOnClickListener(mOnSnoozeClick); */ - if (mAppBubble == BUBBLE_PREFERENCE_ALL) { - ((TextView) findViewById(R.id.default_summary)).setText(getResources().getString( + TextView defaultSummaryTextView = findViewById(R.id.default_summary); + if (mAppBubble == BUBBLE_PREFERENCE_ALL + && BubblesManager.areBubblesEnabled(mContext, mSbn.getUser())) { + defaultSummaryTextView.setText(getResources().getString( R.string.notification_channel_summary_default_with_bubbles, mAppName)); + } else { + defaultSummaryTextView.setText(getResources().getString( + R.string.notification_channel_summary_default)); } findViewById(R.id.priority).setOnClickListener(mOnFavoriteClick); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 28356730dab1..b7a605a793bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -427,12 +427,6 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void onHintFinished(); - void onCameraHintStarted(); - - void onVoiceAssistHintStarted(); - - void onPhoneHintStarted(); - void onTrackingStopped(boolean expand); // TODO: Figure out way to remove these. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 9060d5f67913..38c37f03f643 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -388,8 +388,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.reset(true /* hide */); } - mNotificationPanelViewController.launchCamera( - mCentralSurfaces.isDeviceInteractive() /* animate */, source); + mNotificationPanelViewController.launchCamera(source); mCentralSurfaces.updateScrimController(); } else { // We need to defer the camera launch until the screen comes on, since otherwise diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 4ca14598dd36..745b7d92435a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1268,8 +1268,6 @@ public class CentralSurfacesImpl extends CoreStartable implements backdrop.setScaleY(scale); }); - mNotificationPanelViewController.setUserSetupComplete(mUserSetup); - // Set up the quick settings tile panel final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame); if (container != null) { @@ -3007,8 +3005,7 @@ public class CentralSurfacesImpl extends CoreStartable implements @Override public boolean isInLaunchTransition() { - return mNotificationPanelViewController.isLaunchTransitionRunning() - || mNotificationPanelViewController.isLaunchTransitionFinished(); + return mNotificationPanelViewController.isLaunchTransitionFinished(); } /** @@ -3040,11 +3037,7 @@ public class CentralSurfacesImpl extends CoreStartable implements mCommandQueue.appTransitionStarting(mDisplayId, SystemClock.uptimeMillis(), LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); }; - if (mNotificationPanelViewController.isLaunchTransitionRunning()) { - mNotificationPanelViewController.setLaunchTransitionEndRunnable(hideRunnable); - } else { - hideRunnable.run(); - } + hideRunnable.run(); } private void cancelAfterLaunchTransitionRunnables() { @@ -3053,7 +3046,6 @@ public class CentralSurfacesImpl extends CoreStartable implements } mLaunchTransitionEndRunnable = null; mLaunchTransitionCancelRunnable = null; - mNotificationPanelViewController.setLaunchTransitionEndRunnable(null); } /** @@ -3482,24 +3474,6 @@ public class CentralSurfacesImpl extends CoreStartable implements } @Override - public void onCameraHintStarted() { - mFalsingCollector.onCameraHintStarted(); - mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); - } - - @Override - public void onVoiceAssistHintStarted() { - mFalsingCollector.onLeftAffordanceHintStarted(); - mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); - } - - @Override - public void onPhoneHintStarted() { - mFalsingCollector.onLeftAffordanceHintStarted(); - mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); - } - - @Override public void onTrackingStopped(boolean expand) { } @@ -3683,8 +3657,7 @@ public class CentralSurfacesImpl extends CoreStartable implements mWakeUpCoordinator.setFullyAwake(true); mWakeUpCoordinator.setWakingUp(false); if (mLaunchCameraWhenFinishedWaking) { - mNotificationPanelViewController.launchCamera( - false /* animate */, mLastCameraLaunchSource); + mNotificationPanelViewController.launchCamera(mLastCameraLaunchSource); mLaunchCameraWhenFinishedWaking = false; } if (mLaunchEmergencyActionWhenFinishedWaking) { @@ -4326,9 +4299,6 @@ public class CentralSurfacesImpl extends CoreStartable implements if (!mUserSetup) { animateCollapseQuickSettings(); } - if (mNotificationPanelViewController != null) { - mNotificationPanelViewController.setUserSetupComplete(mUserSetup); - } updateQsExpansionEnabled(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java deleted file mode 100644 index 2922b4c98d34..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.content.Context; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; - -import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; -import com.android.systemui.classifier.Classifier; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.statusbar.KeyguardAffordanceView; -import com.android.wm.shell.animation.FlingAnimationUtils; - -/** - * A touch handler of the keyguard which is responsible for launching phone and camera affordances. - */ -public class KeyguardAffordanceHelper { - - public static final long HINT_PHASE1_DURATION = 200; - private static final long HINT_PHASE2_DURATION = 350; - private static final float BACKGROUND_RADIUS_SCALE_FACTOR = 0.25f; - private static final int HINT_CIRCLE_OPEN_DURATION = 500; - - private final Context mContext; - private final Callback mCallback; - - private FlingAnimationUtils mFlingAnimationUtils; - private VelocityTracker mVelocityTracker; - private boolean mSwipingInProgress; - private float mInitialTouchX; - private float mInitialTouchY; - private float mTranslation; - private float mTranslationOnDown; - private int mTouchSlop; - private int mMinTranslationAmount; - private int mMinFlingVelocity; - private int mHintGrowAmount; - private KeyguardAffordanceView mLeftIcon; - private KeyguardAffordanceView mRightIcon; - private Animator mSwipeAnimator; - private final FalsingManager mFalsingManager; - private int mMinBackgroundRadius; - private boolean mMotionCancelled; - private int mTouchTargetSize; - private View mTargetedView; - private boolean mTouchSlopExeeded; - private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mSwipeAnimator = null; - mSwipingInProgress = false; - mTargetedView = null; - } - }; - private Runnable mAnimationEndRunnable = new Runnable() { - @Override - public void run() { - mCallback.onAnimationToSideEnded(); - } - }; - - KeyguardAffordanceHelper(Callback callback, Context context, FalsingManager falsingManager) { - mContext = context; - mCallback = callback; - initIcons(); - updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true, false); - updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true, false); - mFalsingManager = falsingManager; - initDimens(); - } - - private void initDimens() { - final ViewConfiguration configuration = ViewConfiguration.get(mContext); - mTouchSlop = configuration.getScaledPagingTouchSlop(); - mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity(); - mMinTranslationAmount = mContext.getResources().getDimensionPixelSize( - R.dimen.keyguard_min_swipe_amount); - mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( - R.dimen.keyguard_affordance_min_background_radius); - mTouchTargetSize = mContext.getResources().getDimensionPixelSize( - R.dimen.keyguard_affordance_touch_target_size); - mHintGrowAmount = - mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways); - mFlingAnimationUtils = new FlingAnimationUtils(mContext.getResources().getDisplayMetrics(), - 0.4f); - } - - private void initIcons() { - mLeftIcon = mCallback.getLeftIcon(); - mRightIcon = mCallback.getRightIcon(); - updatePreviews(); - } - - public void updatePreviews() { - mLeftIcon.setPreviewView(mCallback.getLeftPreview()); - mRightIcon.setPreviewView(mCallback.getRightPreview()); - } - - public boolean onTouchEvent(MotionEvent event) { - int action = event.getActionMasked(); - if (mMotionCancelled && action != MotionEvent.ACTION_DOWN) { - return false; - } - final float y = event.getY(); - final float x = event.getX(); - - boolean isUp = false; - switch (action) { - case MotionEvent.ACTION_DOWN: - View targetView = getIconAtPosition(x, y); - if (targetView == null || (mTargetedView != null && mTargetedView != targetView)) { - mMotionCancelled = true; - return false; - } - if (mTargetedView != null) { - cancelAnimation(); - } else { - mTouchSlopExeeded = false; - } - startSwiping(targetView); - mInitialTouchX = x; - mInitialTouchY = y; - mTranslationOnDown = mTranslation; - initVelocityTracker(); - trackMovement(event); - mMotionCancelled = false; - break; - case MotionEvent.ACTION_POINTER_DOWN: - mMotionCancelled = true; - endMotion(true /* forceSnapBack */, x, y); - break; - case MotionEvent.ACTION_MOVE: - trackMovement(event); - float xDist = x - mInitialTouchX; - float yDist = y - mInitialTouchY; - float distance = (float) Math.hypot(xDist, yDist); - if (!mTouchSlopExeeded && distance > mTouchSlop) { - mTouchSlopExeeded = true; - } - if (mSwipingInProgress) { - if (mTargetedView == mRightIcon) { - distance = mTranslationOnDown - distance; - distance = Math.min(0, distance); - } else { - distance = mTranslationOnDown + distance; - distance = Math.max(0, distance); - } - setTranslation(distance, false /* isReset */, false /* animateReset */); - } - break; - - case MotionEvent.ACTION_UP: - isUp = true; - case MotionEvent.ACTION_CANCEL: - boolean hintOnTheRight = mTargetedView == mRightIcon; - trackMovement(event); - endMotion(!isUp, x, y); - if (!mTouchSlopExeeded && isUp) { - mCallback.onIconClicked(hintOnTheRight); - } - break; - } - return true; - } - - private void startSwiping(View targetView) { - mCallback.onSwipingStarted(targetView == mRightIcon); - mSwipingInProgress = true; - mTargetedView = targetView; - } - - private View getIconAtPosition(float x, float y) { - if (leftSwipePossible() && isOnIcon(mLeftIcon, x, y)) { - return mLeftIcon; - } - if (rightSwipePossible() && isOnIcon(mRightIcon, x, y)) { - return mRightIcon; - } - return null; - } - - public boolean isOnAffordanceIcon(float x, float y) { - return isOnIcon(mLeftIcon, x, y) || isOnIcon(mRightIcon, x, y); - } - - private boolean isOnIcon(View icon, float x, float y) { - float iconX = icon.getX() + icon.getWidth() / 2.0f; - float iconY = icon.getY() + icon.getHeight() / 2.0f; - double distance = Math.hypot(x - iconX, y - iconY); - return distance <= mTouchTargetSize / 2; - } - - private void endMotion(boolean forceSnapBack, float lastX, float lastY) { - if (mSwipingInProgress) { - flingWithCurrentVelocity(forceSnapBack, lastX, lastY); - } else { - mTargetedView = null; - } - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - - private boolean rightSwipePossible() { - return mRightIcon.getVisibility() == View.VISIBLE; - } - - private boolean leftSwipePossible() { - return mLeftIcon.getVisibility() == View.VISIBLE; - } - - public boolean onInterceptTouchEvent(MotionEvent ev) { - return false; - } - - public void startHintAnimation(boolean right, - Runnable onFinishedListener) { - cancelAnimation(); - startHintAnimationPhase1(right, onFinishedListener); - } - - private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) { - final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; - ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount); - animator.addListener(new AnimatorListenerAdapter() { - private boolean mCancelled; - - @Override - public void onAnimationCancel(Animator animation) { - mCancelled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - if (mCancelled) { - mSwipeAnimator = null; - mTargetedView = null; - onFinishedListener.run(); - } else { - startUnlockHintAnimationPhase2(right, onFinishedListener); - } - } - }); - animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - animator.setDuration(HINT_PHASE1_DURATION); - animator.start(); - mSwipeAnimator = animator; - mTargetedView = targetView; - } - - /** - * Phase 2: Move back. - */ - private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) { - ValueAnimator animator = getAnimatorToRadius(right, 0); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mSwipeAnimator = null; - mTargetedView = null; - onFinishedListener.run(); - } - }); - animator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); - animator.setDuration(HINT_PHASE2_DURATION); - animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION); - animator.start(); - mSwipeAnimator = animator; - } - - private ValueAnimator getAnimatorToRadius(final boolean right, int radius) { - final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; - ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float newRadius = (float) animation.getAnimatedValue(); - targetView.setCircleRadiusWithoutAnimation(newRadius); - float translation = getTranslationFromRadius(newRadius); - mTranslation = right ? -translation : translation; - updateIconsFromTranslation(targetView); - } - }); - return animator; - } - - private void cancelAnimation() { - if (mSwipeAnimator != null) { - mSwipeAnimator.cancel(); - } - } - - private void flingWithCurrentVelocity(boolean forceSnapBack, float lastX, float lastY) { - float vel = getCurrentVelocity(lastX, lastY); - - // We snap back if the current translation is not far enough - boolean snapBack = false; - if (mCallback.needsAntiFalsing()) { - snapBack = snapBack || mFalsingManager.isFalseTouch( - mTargetedView == mRightIcon - ? Classifier.RIGHT_AFFORDANCE : Classifier.LEFT_AFFORDANCE); - } - snapBack = snapBack || isBelowFalsingThreshold(); - - // or if the velocity is in the opposite direction. - boolean velIsInWrongDirection = vel * mTranslation < 0; - snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection; - vel = snapBack ^ velIsInWrongDirection ? 0 : vel; - fling(vel, snapBack || forceSnapBack, mTranslation < 0); - } - - private boolean isBelowFalsingThreshold() { - return Math.abs(mTranslation) < Math.abs(mTranslationOnDown) + getMinTranslationAmount(); - } - - private int getMinTranslationAmount() { - float factor = mCallback.getAffordanceFalsingFactor(); - return (int) (mMinTranslationAmount * factor); - } - - private void fling(float vel, final boolean snapBack, boolean right) { - float target = right ? -mCallback.getMaxTranslationDistance() - : mCallback.getMaxTranslationDistance(); - target = snapBack ? 0 : target; - - ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target); - mFlingAnimationUtils.apply(animator, mTranslation, target, vel); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mTranslation = (float) animation.getAnimatedValue(); - } - }); - animator.addListener(mFlingEndListener); - if (!snapBack) { - startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable, right); - mCallback.onAnimationToSideStarted(right, mTranslation, vel); - } else { - reset(true); - } - animator.start(); - mSwipeAnimator = animator; - if (snapBack) { - mCallback.onSwipingAborted(); - } - } - - private void startFinishingCircleAnimation(float velocity, Runnable animationEndRunnable, - boolean right) { - KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; - targetView.finishAnimation(velocity, animationEndRunnable); - } - - private void setTranslation(float translation, boolean isReset, boolean animateReset) { - translation = rightSwipePossible() ? translation : Math.max(0, translation); - translation = leftSwipePossible() ? translation : Math.min(0, translation); - float absTranslation = Math.abs(translation); - if (translation != mTranslation || isReset) { - KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon; - KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon; - float alpha = absTranslation / getMinTranslationAmount(); - - // We interpolate the alpha of the other icons to 0 - float fadeOutAlpha = 1.0f - alpha; - fadeOutAlpha = Math.max(fadeOutAlpha, 0.0f); - - boolean animateIcons = isReset && animateReset; - boolean forceNoCircleAnimation = isReset && !animateReset; - float radius = getRadiusFromTranslation(absTranslation); - boolean slowAnimation = isReset && isBelowFalsingThreshold(); - if (!isReset) { - updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(), - false, false, false, false); - } else { - updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(), - animateIcons, slowAnimation, true /* isReset */, forceNoCircleAnimation); - } - updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(), - animateIcons, slowAnimation, isReset, forceNoCircleAnimation); - - mTranslation = translation; - } - } - - private void updateIconsFromTranslation(KeyguardAffordanceView targetView) { - float absTranslation = Math.abs(mTranslation); - float alpha = absTranslation / getMinTranslationAmount(); - - // We interpolate the alpha of the other icons to 0 - float fadeOutAlpha = 1.0f - alpha; - fadeOutAlpha = Math.max(0.0f, fadeOutAlpha); - - // We interpolate the alpha of the targetView to 1 - KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon; - updateIconAlpha(targetView, alpha + fadeOutAlpha * targetView.getRestingAlpha(), false); - updateIconAlpha(otherView, fadeOutAlpha * otherView.getRestingAlpha(), false); - } - - private float getTranslationFromRadius(float circleSize) { - float translation = (circleSize - mMinBackgroundRadius) - / BACKGROUND_RADIUS_SCALE_FACTOR; - return translation > 0.0f ? translation + mTouchSlop : 0.0f; - } - - private float getRadiusFromTranslation(float translation) { - if (translation <= mTouchSlop) { - return 0.0f; - } - return (translation - mTouchSlop) * BACKGROUND_RADIUS_SCALE_FACTOR + mMinBackgroundRadius; - } - - public void animateHideLeftRightIcon() { - cancelAnimation(); - updateIcon(mRightIcon, 0f, 0f, true, false, false, false); - updateIcon(mLeftIcon, 0f, 0f, true, false, false, false); - } - - private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha, - boolean animate, boolean slowRadiusAnimation, boolean force, - boolean forceNoCircleAnimation) { - if (view.getVisibility() != View.VISIBLE && !force) { - return; - } - if (forceNoCircleAnimation) { - view.setCircleRadiusWithoutAnimation(circleRadius); - } else { - view.setCircleRadius(circleRadius, slowRadiusAnimation); - } - updateIconAlpha(view, alpha, animate); - } - - private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) { - float scale = getScale(alpha, view); - alpha = Math.min(1.0f, alpha); - view.setImageAlpha(alpha, animate); - view.setImageScale(scale, animate); - } - - private float getScale(float alpha, KeyguardAffordanceView icon) { - float scale = alpha / icon.getRestingAlpha() * 0.2f + - KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT; - return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT); - } - - private void trackMovement(MotionEvent event) { - if (mVelocityTracker != null) { - mVelocityTracker.addMovement(event); - } - } - - private void initVelocityTracker() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - } - mVelocityTracker = VelocityTracker.obtain(); - } - - private float getCurrentVelocity(float lastX, float lastY) { - if (mVelocityTracker == null) { - return 0; - } - mVelocityTracker.computeCurrentVelocity(1000); - float aX = mVelocityTracker.getXVelocity(); - float aY = mVelocityTracker.getYVelocity(); - float bX = lastX - mInitialTouchX; - float bY = lastY - mInitialTouchY; - float bLen = (float) Math.hypot(bX, bY); - // Project the velocity onto the distance vector: a * b / |b| - float projectedVelocity = (aX * bX + aY * bY) / bLen; - if (mTargetedView == mRightIcon) { - projectedVelocity = -projectedVelocity; - } - return projectedVelocity; - } - - public void onConfigurationChanged() { - initDimens(); - initIcons(); - } - - public void onRtlPropertiesChanged() { - initIcons(); - } - - public void reset(boolean animate) { - cancelAnimation(); - setTranslation(0.0f, true /* isReset */, animate); - mMotionCancelled = true; - if (mSwipingInProgress) { - mCallback.onSwipingAborted(); - mSwipingInProgress = false; - } - } - - public boolean isSwipingInProgress() { - return mSwipingInProgress; - } - - public void launchAffordance(boolean animate, boolean left) { - if (mSwipingInProgress) { - // We don't want to mess with the state if the user is actually swiping already. - return; - } - KeyguardAffordanceView targetView = left ? mLeftIcon : mRightIcon; - KeyguardAffordanceView otherView = left ? mRightIcon : mLeftIcon; - startSwiping(targetView); - - // Do not animate the circle expanding if the affordance isn't visible, - // otherwise the circle will be meaningless. - if (targetView.getVisibility() != View.VISIBLE) { - animate = false; - } - - if (animate) { - fling(0, false, !left); - updateIcon(otherView, 0.0f, 0, true, false, true, false); - } else { - mCallback.onAnimationToSideStarted(!left, mTranslation, 0); - mTranslation = left ? mCallback.getMaxTranslationDistance() - : mCallback.getMaxTranslationDistance(); - updateIcon(otherView, 0.0f, 0.0f, false, false, true, false); - targetView.instantFinishAnimation(); - mFlingEndListener.onAnimationEnd(null); - mAnimationEndRunnable.run(); - } - } - - public interface Callback { - - /** - * Notifies the callback when an animation to a side page was started. - * - * @param rightPage Is the page animated to the right page? - */ - void onAnimationToSideStarted(boolean rightPage, float translation, float vel); - - /** - * Notifies the callback the animation to a side page has ended. - */ - void onAnimationToSideEnded(); - - float getMaxTranslationDistance(); - - void onSwipingStarted(boolean rightIcon); - - void onSwipingAborted(); - - void onIconClicked(boolean rightIcon); - - KeyguardAffordanceView getLeftIcon(); - - KeyguardAffordanceView getRightIcon(); - - View getLeftPreview(); - - View getRightPreview(); - - /** - * @return The factor the minimum swipe amount should be multiplied with. - */ - float getAffordanceFalsingFactor(); - - boolean needsAntiFalsing(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index b43e9df79241..52c04b9de29a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -16,47 +16,30 @@ package com.android.systemui.statusbar.phone; -import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; -import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; - import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; -import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON; -import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK; -import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON; -import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE; -import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.service.quickaccesswallet.GetWalletCardsError; import android.service.quickaccesswallet.GetWalletCardsResponse; import android.service.quickaccesswallet.QuickAccessWalletClient; -import android.telecom.TelecomManager; -import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -64,81 +47,35 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.Utils; -import com.android.systemui.ActivityIntentHelper; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.Interpolators; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.camera.CameraIntents; -import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.controls.ui.ControlsActivity; import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.IntentButtonProvider; -import com.android.systemui.plugins.IntentButtonProvider.IntentButton; -import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; -import com.android.systemui.statusbar.KeyguardAffordanceView; -import com.android.systemui.statusbar.policy.AccessibilityController; -import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.policy.ExtensionController.Extension; -import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.PreviewInflater; -import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory; -import com.android.systemui.tuner.TunerService; import com.android.systemui.wallet.controller.QuickAccessWalletController; -import java.util.List; - /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status * text. */ -public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener, - KeyguardStateController.Callback, - AccessibilityController.AccessibilityStateChangedCallback { - - final static String TAG = "CentralSurfaces/KeyguardBottomAreaView"; - - public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance"; - public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture"; - public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap"; - public static final String CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = "lift_to_launch_ml"; - - public static final String EXTRA_CAMERA_LAUNCH_SOURCE - = "com.android.systemui.camera_launch_source"; - - private static final String LEFT_BUTTON_PLUGIN - = "com.android.systemui.action.PLUGIN_LOCKSCREEN_LEFT_BUTTON"; - private static final String RIGHT_BUTTON_PLUGIN - = "com.android.systemui.action.PLUGIN_LOCKSCREEN_RIGHT_BUTTON"; +public class KeyguardBottomAreaView extends FrameLayout { - private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL); - private static final int DOZE_ANIMATION_STAGGER_DELAY = 48; + private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView"; private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250; - // TODO(b/179494051): May no longer be needed - private final boolean mShowLeftAffordance; - private final boolean mShowCameraAffordance; - - private KeyguardAffordanceView mRightAffordanceView; - private KeyguardAffordanceView mLeftAffordanceView; - private ImageView mWalletButton; private ImageView mQRCodeScannerButton; private ImageView mControlsButton; private boolean mHasCard = false; - private WalletCardRetriever mCardRetriever = new WalletCardRetriever(); + private final WalletCardRetriever mCardRetriever = new WalletCardRetriever(); private QuickAccessWalletController mQuickAccessWalletController; private QRCodeScannerController mQRCodeScannerController; private ControlsComponent mControlsComponent; @@ -148,54 +85,42 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private ViewGroup mIndicationArea; private TextView mIndicationText; private TextView mIndicationTextBottom; - private ViewGroup mPreviewContainer; private ViewGroup mOverlayContainer; - private View mLeftPreview; - private View mCameraPreview; - private ActivityStarter mActivityStarter; private KeyguardStateController mKeyguardStateController; - private FlashlightController mFlashlightController; - private PreviewInflater mPreviewInflater; - private AccessibilityController mAccessibilityController; private CentralSurfaces mCentralSurfaces; - private KeyguardAffordanceHelper mAffordanceHelper; private FalsingManager mFalsingManager; - private boolean mUserSetupComplete; - private boolean mLeftIsVoiceAssist; - private Drawable mLeftAssistIcon; - - private IntentButton mRightButton = new DefaultRightButton(); - private Extension<IntentButton> mRightExtension; - private String mRightButtonStr; - private IntentButton mLeftButton = new DefaultLeftButton(); - private Extension<IntentButton> mLeftExtension; - private String mLeftButtonStr; private boolean mDozing; private int mIndicationBottomMargin; private int mIndicationPadding; private float mDarkAmount; private int mBurnInXOffset; private int mBurnInYOffset; - private ActivityIntentHelper mActivityIntentHelper; - private KeyguardUpdateMonitor mKeyguardUpdateMonitor; - - private ControlsListingController.ControlsListingCallback mListingCallback = - new ControlsListingController.ControlsListingCallback() { - public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) { - post(() -> { - boolean available = !serviceInfos.isEmpty(); - - if (available != mControlServicesAvailable) { - mControlServicesAvailable = available; - updateControlsVisibility(); - updateAffordanceColors(); - } - }); + + private final ControlsListingController.ControlsListingCallback mListingCallback = + serviceInfos -> post(() -> { + boolean available = !serviceInfos.isEmpty(); + + if (available != mControlServicesAvailable) { + mControlServicesAvailable = available; + updateControlsVisibility(); + updateAffordanceColors(); } - }; + }); + + private final KeyguardStateController.Callback mKeyguardStateCallback = + new KeyguardStateController.Callback() { + @Override + public void onKeyguardShowingChanged() { + if (mKeyguardStateController.isShowing()) { + if (mQuickAccessWalletController != null) { + mQuickAccessWalletController.queryWalletCards(mCardRetriever); + } + } + } + }; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -212,43 +137,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mShowLeftAffordance = getResources().getBoolean(R.bool.config_keyguardShowLeftAffordance); - mShowCameraAffordance = getResources() - .getBoolean(R.bool.config_keyguardShowCameraAffordance); } - private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() { - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - String label = null; - if (host == mRightAffordanceView) { - label = getResources().getString(R.string.camera_label); - } else if (host == mLeftAffordanceView) { - if (mLeftIsVoiceAssist) { - label = getResources().getString(R.string.voice_assist_label); - } else { - label = getResources().getString(R.string.phone_label); - } - } - info.addAction(new AccessibilityAction(ACTION_CLICK, label)); - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if (action == ACTION_CLICK) { - if (host == mRightAffordanceView) { - launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); - return true; - } else if (host == mLeftAffordanceView) { - launchLeftAffordance(); - return true; - } - } - return super.performAccessibilityAction(host, action, args); - } - }; - public void initFrom(KeyguardBottomAreaView oldBottomArea) { setCentralSurfaces(oldBottomArea.mCentralSurfaces); @@ -279,11 +169,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override protected void onFinishInflate() { super.onFinishInflate(); - mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext), - new ActivityIntentHelper(mContext)); mOverlayContainer = findViewById(R.id.overlay_container); - mRightAffordanceView = findViewById(R.id.camera_button); - mLeftAffordanceView = findViewById(R.id.left_button); mWalletButton = findViewById(R.id.wallet_button); mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button); mControlsButton = findViewById(R.id.controls_button); @@ -295,18 +181,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL R.dimen.keyguard_indication_margin_bottom); mBurnInYOffset = getResources().getDimensionPixelSize( R.dimen.default_burn_in_prevention_offset); - updateCameraVisibility(); mKeyguardStateController = Dependency.get(KeyguardStateController.class); - mKeyguardStateController.addCallback(this); + mKeyguardStateController.addCallback(mKeyguardStateCallback); setClipChildren(false); setClipToPadding(false); - mRightAffordanceView.setOnClickListener(this); - mLeftAffordanceView.setOnClickListener(this); - initAccessibility(); mActivityStarter = Dependency.get(ActivityStarter.class); - mFlashlightController = Dependency.get(FlashlightController.class); - mAccessibilityController = Dependency.get(AccessibilityController.class); - mActivityIntentHelper = new ActivityIntentHelper(getContext()); mIndicationPadding = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_area_padding); @@ -315,51 +194,18 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateControlsVisibility(); } - /** - * Set the container where the previews are rendered. - */ - public void setPreviewContainer(ViewGroup previewContainer) { - mPreviewContainer = previewContainer; - inflateCameraPreview(); - updateLeftAffordance(); - } - @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mAccessibilityController.addStateChangedCallback(this); - mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) - .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN, - p -> p.getIntentButton()) - .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON)) - .withDefault(() -> new DefaultRightButton()) - .withCallback(button -> setRightButton(button)) - .build(); - mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class) - .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN, - p -> p.getIntentButton()) - .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON)) - .withDefault(() -> new DefaultLeftButton()) - .withCallback(button -> setLeftButton(button)) - .build(); final IntentFilter filter = new IntentFilter(); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); - getContext().registerReceiverAsUser(mDevicePolicyReceiver, - UserHandle.ALL, filter, null, null); - mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); - mKeyguardStateController.addCallback(this); + mKeyguardStateController.addCallback(mKeyguardStateCallback); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mKeyguardStateController.removeCallback(this); - mAccessibilityController.removeStateChangedCallback(this); - mRightExtension.destroy(); - mLeftExtension.destroy(); - getContext().unregisterReceiver(mDevicePolicyReceiver); - mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); + mKeyguardStateController.removeCallback(mKeyguardStateCallback); if (mQuickAccessWalletController != null) { mQuickAccessWalletController.unregisterWalletChangeObservers( @@ -378,11 +224,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - private void initAccessibility() { - mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate); - mRightAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate); - } - @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -404,19 +245,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL getResources().getDimensionPixelSize( com.android.internal.R.dimen.text_size_small_material)); - ViewGroup.LayoutParams lp = mRightAffordanceView.getLayoutParams(); - lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width); - lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height); - mRightAffordanceView.setLayoutParams(lp); - updateRightAffordanceIcon(); - - lp = mLeftAffordanceView.getLayoutParams(); - lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width); - lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height); - mLeftAffordanceView.setLayoutParams(lp); - updateLeftAffordanceIcon(); - - lp = mWalletButton.getLayoutParams(); + ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams(); lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width); lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height); mWalletButton.setLayoutParams(lp); @@ -439,74 +268,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateAffordanceColors(); } - private void updateRightAffordanceIcon() { - IconState state = mRightButton.getIcon(); - mRightAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE); - if (state.drawable != mRightAffordanceView.getDrawable() - || state.tint != mRightAffordanceView.shouldTint()) { - mRightAffordanceView.setImageDrawable(state.drawable, state.tint); - } - mRightAffordanceView.setContentDescription(state.contentDescription); - } - public void setCentralSurfaces(CentralSurfaces centralSurfaces) { mCentralSurfaces = centralSurfaces; - updateCameraVisibility(); // in case onFinishInflate() was called too early - } - - public void setAffordanceHelper(KeyguardAffordanceHelper affordanceHelper) { - mAffordanceHelper = affordanceHelper; - } - - public void setUserSetupComplete(boolean userSetupComplete) { - mUserSetupComplete = userSetupComplete; - updateCameraVisibility(); - updateLeftAffordanceIcon(); - } - - private Intent getCameraIntent() { - return mRightButton.getIntent(); - } - - /** - * Resolves the intent to launch the camera application. - */ - public ResolveInfo resolveCameraIntent() { - return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), - PackageManager.MATCH_DEFAULT_ONLY, - KeyguardUpdateMonitor.getCurrentUser()); - } - - private void updateCameraVisibility() { - if (mRightAffordanceView == null) { - // Things are not set up yet; reply hazy, ask again later - return; - } - mRightAffordanceView.setVisibility(!mDozing && mShowCameraAffordance - && mRightButton.getIcon().isVisible ? View.VISIBLE : View.GONE); - } - - /** - * Set an alternate icon for the left assist affordance (replace the mic icon) - */ - public void setLeftAssistIcon(Drawable drawable) { - mLeftAssistIcon = drawable; - updateLeftAffordanceIcon(); - } - - private void updateLeftAffordanceIcon() { - if (!mShowLeftAffordance || mDozing) { - mLeftAffordanceView.setVisibility(GONE); - return; - } - - IconState state = mLeftButton.getIcon(); - mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE); - if (state.drawable != mLeftAffordanceView.getDrawable() - || state.tint != mLeftAffordanceView.shouldTint()) { - mLeftAffordanceView.setImageDrawable(state.drawable, state.tint); - } - mLeftAffordanceView.setContentDescription(state.contentDescription); } private void updateWalletVisibility() { @@ -552,73 +315,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - public boolean isLeftVoiceAssist() { - return mLeftIsVoiceAssist; - } - - private boolean isPhoneVisible() { - PackageManager pm = mContext.getPackageManager(); - return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) - && pm.resolveActivity(PHONE_INTENT, 0) != null; - } - - @Override - public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) { - mRightAffordanceView.setClickable(touchExplorationEnabled); - mLeftAffordanceView.setClickable(touchExplorationEnabled); - mRightAffordanceView.setFocusable(accessibilityEnabled); - mLeftAffordanceView.setFocusable(accessibilityEnabled); - } - - @Override - public void onClick(View v) { - if (v == mRightAffordanceView) { - launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); - } else if (v == mLeftAffordanceView) { - launchLeftAffordance(); - } - } - - public void launchCamera(String source) { - final Intent intent = getCameraIntent(); - intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source); - boolean wouldLaunchResolverActivity = mActivityIntentHelper.wouldLaunchResolverActivity( - intent, KeyguardUpdateMonitor.getCurrentUser()); - if (CameraIntents.isSecureCameraIntent(intent) && !wouldLaunchResolverActivity) { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - // Normally an activity will set it's requested rotation - // animation on its window. However when launching an activity - // causes the orientation to change this is too late. In these cases - // the default animation is used. This doesn't look good for - // the camera (as it rotates the camera contents out of sync - // with physical reality). So, we ask the WindowManager to - // force the crossfade animation if an orientation change - // happens to occur during the launch. - ActivityOptions o = ActivityOptions.makeBasic(); - o.setDisallowEnterPictureInPictureWhileLaunching(true); - o.setRotationAnimationHint( - WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); - try { - ActivityTaskManager.getService().startActivityAsUser( - null, getContext().getBasePackageName(), - getContext().getAttributionTag(), intent, - intent.resolveTypeIfNeeded(getContext().getContentResolver()), - null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(), - UserHandle.CURRENT.getIdentifier()); - } catch (RemoteException e) { - Log.w(TAG, "Unable to start camera activity", e); - } - } - }); - } else { - // We need to delay starting the activity because ResolverActivity finishes itself if - // launched behind lockscreen. - mActivityStarter.startActivity(intent, false /* dismissShade */); - } - } - public void setDarkAmount(float darkAmount) { if (darkAmount == mDarkAmount) { return; @@ -627,77 +323,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL dozeTimeTick(); } - public void launchLeftAffordance() { - if (mLeftIsVoiceAssist) { - launchVoiceAssist(); - } else { - launchPhone(); - } - } - - @VisibleForTesting - void launchVoiceAssist() { - Runnable runnable = new Runnable() { - @Override - public void run() { - Dependency.get(AssistManager.class).launchVoiceAssistFromKeyguard(); - } - }; - if (!mKeyguardStateController.canDismissLockScreen()) { - Dependency.get(Dependency.BACKGROUND_EXECUTOR).execute(runnable); - } else { - boolean dismissShade = !TextUtils.isEmpty(mRightButtonStr) - && Dependency.get(TunerService.class).getValue(LOCKSCREEN_RIGHT_UNLOCK, 1) != 0; - mCentralSurfaces.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */, - dismissShade, false /* afterKeyguardGone */, true /* deferred */); - } - } - - private boolean canLaunchVoiceAssist() { - return Dependency.get(AssistManager.class).canVoiceAssistBeLaunchedFromKeyguard(); - } - - private void launchPhone() { - final TelecomManager tm = TelecomManager.from(mContext); - if (tm.isInCall()) { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - tm.showInCallScreen(false /* showDialpad */); - } - }); - } else { - boolean dismissShade = !TextUtils.isEmpty(mLeftButtonStr) - && Dependency.get(TunerService.class).getValue(LOCKSCREEN_LEFT_UNLOCK, 1) != 0; - mActivityStarter.startActivity(mLeftButton.getIntent(), dismissShade); - } - } - - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - if (changedView == this && visibility == VISIBLE) { - updateCameraVisibility(); - } - } - - public KeyguardAffordanceView getLeftView() { - return mLeftAffordanceView; - } - - public KeyguardAffordanceView getRightView() { - return mRightAffordanceView; - } - - public View getLeftPreview() { - return mLeftPreview; - } - - public View getRightPreview() { - return mCameraPreview; - } - public View getIndicationArea() { return mIndicationArea; } @@ -707,66 +332,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return false; } - @Override - public void onUnlockedChanged() { - updateCameraVisibility(); - } - - @Override - public void onKeyguardShowingChanged() { - if (mKeyguardStateController.isShowing()) { - if (mQuickAccessWalletController != null) { - mQuickAccessWalletController.queryWalletCards(mCardRetriever); - } - } - } - - private void inflateCameraPreview() { - if (mPreviewContainer == null) { - return; - } - View previewBefore = mCameraPreview; - boolean visibleBefore = false; - if (previewBefore != null) { - mPreviewContainer.removeView(previewBefore); - visibleBefore = previewBefore.getVisibility() == View.VISIBLE; - } - mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); - if (mCameraPreview != null) { - mPreviewContainer.addView(mCameraPreview); - mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE); - } - if (mAffordanceHelper != null) { - mAffordanceHelper.updatePreviews(); - } - } - - private void updateLeftPreview() { - if (mPreviewContainer == null) { - return; - } - View previewBefore = mLeftPreview; - if (previewBefore != null) { - mPreviewContainer.removeView(previewBefore); - } - - if (mLeftIsVoiceAssist) { - if (Dependency.get(AssistManager.class).getVoiceInteractorComponentName() != null) { - mLeftPreview = mPreviewInflater.inflatePreviewFromService( - Dependency.get(AssistManager.class).getVoiceInteractorComponentName()); - } - } else { - mLeftPreview = mPreviewInflater.inflatePreview(mLeftButton.getIntent()); - } - if (mLeftPreview != null) { - mPreviewContainer.addView(mLeftPreview); - mLeftPreview.setVisibility(View.INVISIBLE); - } - if (mAffordanceHelper != null) { - mAffordanceHelper.updatePreviews(); - } - } - public void startFinishDozeAnimation() { long delay = 0; if (mWalletButton.getVisibility() == View.VISIBLE) { @@ -778,13 +343,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL if (mControlsButton.getVisibility() == View.VISIBLE) { startFinishDozeAnimationElement(mControlsButton, delay); } - if (mLeftAffordanceView.getVisibility() == View.VISIBLE) { - startFinishDozeAnimationElement(mLeftAffordanceView, delay); - delay += DOZE_ANIMATION_STAGGER_DELAY; - } - if (mRightAffordanceView.getVisibility() == View.VISIBLE) { - startFinishDozeAnimationElement(mRightAffordanceView, delay); - } } private void startFinishDozeAnimationElement(View element, long delay) { @@ -798,58 +356,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL .setDuration(DOZE_ANIMATION_ELEMENT_DURATION); } - private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - post(new Runnable() { - @Override - public void run() { - updateCameraVisibility(); - } - }); - } - }; - - private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = - new KeyguardUpdateMonitorCallback() { - @Override - public void onUserSwitchComplete(int userId) { - updateCameraVisibility(); - } - - @Override - public void onUserUnlocked() { - inflateCameraPreview(); - updateCameraVisibility(); - updateLeftAffordance(); - } - }; - - public void updateLeftAffordance() { - updateLeftAffordanceIcon(); - updateLeftPreview(); - } - - private void setRightButton(IntentButton button) { - mRightButton = button; - updateRightAffordanceIcon(); - updateCameraVisibility(); - inflateCameraPreview(); - } - - private void setLeftButton(IntentButton button) { - mLeftButton = button; - if (!(mLeftButton instanceof DefaultLeftButton)) { - mLeftIsVoiceAssist = false; - } - updateLeftAffordance(); - } - public void setDozing(boolean dozing, boolean animate) { mDozing = dozing; - updateCameraVisibility(); - updateLeftAffordanceIcon(); updateWalletVisibility(); updateControlsVisibility(); updateQRCodeButtonVisibility(); @@ -888,77 +397,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL * Sets the alpha of the indication areas and affordances, excluding the lock icon. */ public void setAffordanceAlpha(float alpha) { - mLeftAffordanceView.setAlpha(alpha); - mRightAffordanceView.setAlpha(alpha); mIndicationArea.setAlpha(alpha); mWalletButton.setAlpha(alpha); mQRCodeScannerButton.setAlpha(alpha); mControlsButton.setAlpha(alpha); } - private class DefaultLeftButton implements IntentButton { - - private IconState mIconState = new IconState(); - - @Override - public IconState getIcon() { - mLeftIsVoiceAssist = canLaunchVoiceAssist(); - if (mLeftIsVoiceAssist) { - mIconState.isVisible = mUserSetupComplete && mShowLeftAffordance; - if (mLeftAssistIcon == null) { - mIconState.drawable = mContext.getDrawable(R.drawable.ic_mic_26dp); - } else { - mIconState.drawable = mLeftAssistIcon; - } - mIconState.contentDescription = mContext.getString( - R.string.accessibility_voice_assist_button); - } else { - mIconState.isVisible = mUserSetupComplete && mShowLeftAffordance - && isPhoneVisible(); - mIconState.drawable = mContext.getDrawable( - com.android.internal.R.drawable.ic_phone); - mIconState.contentDescription = mContext.getString( - R.string.accessibility_phone_button); - } - return mIconState; - } - - @Override - public Intent getIntent() { - return PHONE_INTENT; - } - } - - private class DefaultRightButton implements IntentButton { - - private IconState mIconState = new IconState(); - - @Override - public IconState getIcon() { - boolean isCameraDisabled = (mCentralSurfaces != null) - && !mCentralSurfaces.isCameraAllowedByAdmin(); - mIconState.isVisible = !isCameraDisabled - && mShowCameraAffordance - && mUserSetupComplete - && resolveCameraIntent() != null; - mIconState.drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp); - mIconState.contentDescription = - mContext.getString(R.string.accessibility_camera_button); - return mIconState; - } - - @Override - public Intent getIntent() { - boolean canDismissLs = mKeyguardStateController.canDismissLockScreen(); - boolean secure = mKeyguardStateController.isMethodSecure(); - if (secure && !canDismissLs) { - return CameraIntents.getSecureCameraIntent(getContext()); - } else { - return CameraIntents.getInsecureCameraIntent(getContext()); - } - } - } - @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { int bottom = insets.getDisplayCutout() != null diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index b435055d1b16..1fcaeaebea1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -50,8 +50,6 @@ import android.app.ActivityManager; import android.app.Fragment; import android.app.StatusBarManager; import android.content.ContentResolver; -import android.content.pm.ResolveInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Canvas; @@ -145,7 +143,6 @@ import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.GestureRecorder; -import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -252,9 +249,6 @@ public class NotificationPanelViewController extends PanelViewController { private final OnOverscrollTopChangedListener mOnOverscrollTopChangedListener = new OnOverscrollTopChangedListener(); - private final KeyguardAffordanceHelperCallback - mKeyguardAffordanceHelperCallback = - new KeyguardAffordanceHelperCallback(); private final OnEmptySpaceClickListener mOnEmptySpaceClickListener = new OnEmptySpaceClickListener(); @@ -333,8 +327,6 @@ public class NotificationPanelViewController extends PanelViewController { // Current max allowed keyguard notifications determined by measuring the panel private int mMaxAllowedKeyguardNotifications; - private ViewGroup mPreviewContainer; - private KeyguardAffordanceHelper mAffordanceHelper; private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController; private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; @@ -434,8 +426,6 @@ public class NotificationPanelViewController extends PanelViewController { */ private boolean mQsAnimatorExpand; private boolean mIsLaunchTransitionFinished; - private boolean mIsLaunchTransitionRunning; - private Runnable mLaunchAnimationEndRunnable; private boolean mOnlyAffordanceInThisMotion; private ValueAnimator mQsSizeChangeAnimator; @@ -452,10 +442,8 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mClosingWithAlphaFadeOut; private boolean mHeadsUpAnimatingAway; private boolean mLaunchingAffordance; - private boolean mAffordanceHasPreview; private final FalsingManager mFalsingManager; private final FalsingCollector mFalsingCollector; - private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; private Runnable mHeadsUpExistenceChangedRunnable = () -> { setHeadsUpAnimatingAway(false); @@ -488,7 +476,6 @@ public class NotificationPanelViewController extends PanelViewController { private float mLinearDarkAmount; private boolean mPulsing; - private boolean mUserSetupComplete; private boolean mHideIconsDuringLaunchAnimation = true; private int mStackScrollerMeasuringPass; /** @@ -1007,8 +994,6 @@ public class NotificationPanelViewController extends PanelViewController { mOnEmptySpaceClickListener); addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp); mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area); - mPreviewContainer = mView.findViewById(R.id.preview_container); - mKeyguardBottomArea.setPreviewContainer(mPreviewContainer); initBottomArea(); @@ -1032,7 +1017,6 @@ public class NotificationPanelViewController extends PanelViewController { mView.setRtlChangeListener(layoutDirection -> { if (layoutDirection != mOldLayoutDirection) { - mAffordanceHelper.onRtlPropertiesChanged(); mOldLayoutDirection = layoutDirection; } }); @@ -1258,7 +1242,6 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea; mKeyguardBottomArea = mKeyguardBottomAreaViewControllerProvider.get().getView(); mKeyguardBottomArea.initFrom(oldBottomArea); - mKeyguardBottomArea.setPreviewContainer(mPreviewContainer); mView.addView(mKeyguardBottomArea, index); initBottomArea(); mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea); @@ -1295,11 +1278,7 @@ public class NotificationPanelViewController extends PanelViewController { } private void initBottomArea() { - mAffordanceHelper = new KeyguardAffordanceHelper( - mKeyguardAffordanceHelperCallback, mView.getContext(), mFalsingManager); - mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper); mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces); - mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete); mKeyguardBottomArea.setFalsingManager(mFalsingManager); mKeyguardBottomArea.initWallet(mQuickAccessWalletController); mKeyguardBottomArea.initControls(mControlsComponent); @@ -1664,10 +1643,6 @@ public class NotificationPanelViewController extends PanelViewController { public void resetViews(boolean animate) { mIsLaunchTransitionFinished = false; mBlockTouches = false; - if (!mLaunchingAffordance) { - mAffordanceHelper.reset(false); - mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; - } mCentralSurfaces.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */, true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); if (animate && !isFullyCollapsed()) { @@ -2210,11 +2185,6 @@ public class NotificationPanelViewController extends PanelViewController { return isFullyCollapsed() || mBarState != StatusBarState.SHADE; } - @Override - protected boolean shouldGestureIgnoreXTouchSlop(float x, float y) { - return !mAffordanceHelper.isOnAffordanceIcon(x, y); - } - private void onQsTouch(MotionEvent event) { int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { @@ -3377,9 +3347,6 @@ public class NotificationPanelViewController extends PanelViewController { mQsExpandImmediate = true; setShowShelfOnly(true); } - if (mBarState == KEYGUARD || mBarState == StatusBarState.SHADE_LOCKED) { - mAffordanceHelper.animateHideLeftRightIcon(); - } mNotificationStackScrollLayoutController.onPanelTrackingStarted(); cancelPendingPanelCollapse(); } @@ -3393,12 +3360,6 @@ public class NotificationPanelViewController extends PanelViewController { true /* animate */); } mNotificationStackScrollLayoutController.onPanelTrackingStopped(); - if (expand && (mBarState == KEYGUARD - || mBarState == StatusBarState.SHADE_LOCKED)) { - if (!mHintAnimationRunning) { - mAffordanceHelper.reset(true); - } - } // If we unlocked from a swipe, the user's finger might still be down after the // unlock animation ends. We need to wait until ACTION_UP to enable blurs again. @@ -3471,10 +3432,6 @@ public class NotificationPanelViewController extends PanelViewController { return mIsLaunchTransitionFinished; } - public boolean isLaunchTransitionRunning() { - return mIsLaunchTransitionRunning; - } - @Override public void setIsLaunchAnimationRunning(boolean running) { boolean wasRunning = mIsLaunchAnimationRunning; @@ -3493,10 +3450,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - public void setLaunchTransitionEndRunnable(Runnable r) { - mLaunchAnimationEndRunnable = r; - } - private void updateDozingVisibilities(boolean animate) { mKeyguardBottomArea.setDozing(mDozing, animate); if (!mDozing && animate) { @@ -3675,30 +3628,8 @@ public class NotificationPanelViewController extends PanelViewController { && mBarState == StatusBarState.SHADE; } - public void launchCamera(boolean animate, int source) { - if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { - mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP; - } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) { - mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE; - } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER) { - mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER; - } else { - - // Default. - mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; - } - - // If we are launching it when we are occluded already we don't want it to animate, - // nor setting these flags, since the occluded state doesn't change anymore, hence it's - // never reset. - if (!isFullyCollapsed()) { - setLaunchingAffordance(true); - } else { - animate = false; - } - mAffordanceHasPreview = mKeyguardBottomArea.getRightPreview() != null; - mAffordanceHelper.launchAffordance( - animate, mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); + /** Launches the camera. */ + public void launchCamera(int source) { } public void onAffordanceLaunchEnded() { @@ -3711,9 +3642,6 @@ public class NotificationPanelViewController extends PanelViewController { */ private void setLaunchingAffordance(boolean launchingAffordance) { mLaunchingAffordance = launchingAffordance; - mKeyguardAffordanceHelperCallback.getLeftIcon().setLaunchingAffordance(launchingAffordance); - mKeyguardAffordanceHelperCallback.getRightIcon().setLaunchingAffordance( - launchingAffordance); mKeyguardBypassController.setLaunchingAffordance(launchingAffordance); } @@ -3721,24 +3649,14 @@ public class NotificationPanelViewController extends PanelViewController { * Return true when a bottom affordance is launching an occluded activity with a splash screen. */ public boolean isLaunchingAffordanceWithPreview() { - return mLaunchingAffordance && mAffordanceHasPreview; + return mLaunchingAffordance; } /** * Whether the camera application can be launched for the camera launch gesture. */ public boolean canCameraGestureBeLaunched() { - if (!mCentralSurfaces.isCameraAllowedByAdmin()) { - return false; - } - - ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent(); - String - packageToLaunch = - (resolveInfo == null || resolveInfo.activityInfo == null) ? null - : resolveInfo.activityInfo.packageName; - return packageToLaunch != null && (mBarState != StatusBarState.SHADE || !isForegroundApp( - packageToLaunch)) && !mAffordanceHelper.isSwipingInProgress(); + return false; } /** @@ -3827,9 +3745,6 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void setTouchAndAnimationDisabled(boolean disabled) { super.setTouchAndAnimationDisabled(disabled); - if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) { - mAffordanceHelper.reset(false /* animate */); - } mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled); } @@ -3912,11 +3827,6 @@ public class NotificationPanelViewController extends PanelViewController { return mKeyguardBottomArea; } - public void setUserSetupComplete(boolean userSetupComplete) { - mUserSetupComplete = userSetupComplete; - mKeyguardBottomArea.setUserSetupComplete(userSetupComplete); - } - public void applyLaunchAnimationProgress(float linearProgress) { boolean hideIcons = LaunchAnimator.getProgress(ActivityLaunchAnimator.TIMINGS, linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; @@ -4271,10 +4181,6 @@ public class NotificationPanelViewController extends PanelViewController { mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1); } boolean handled = false; - if ((!mIsExpanding || mHintAnimationRunning) && !mQsExpanded - && mBarState != StatusBarState.SHADE && !mDozing) { - handled |= mAffordanceHelper.onTouchEvent(event); - } if (mOnlyAffordanceInThisMotion) { return true; } @@ -4517,139 +4423,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - private class KeyguardAffordanceHelperCallback implements KeyguardAffordanceHelper.Callback { - @Override - public void onAnimationToSideStarted(boolean rightPage, float translation, float vel) { - boolean - start = - mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? rightPage - : !rightPage; - mIsLaunchTransitionRunning = true; - mLaunchAnimationEndRunnable = null; - float displayDensity = mCentralSurfaces.getDisplayDensity(); - int lengthDp = Math.abs((int) (translation / displayDensity)); - int velocityDp = Math.abs((int) (vel / displayDensity)); - if (start) { - mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp); - mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER); - mFalsingCollector.onLeftAffordanceOn(); - if (mFalsingCollector.shouldEnforceBouncer()) { - mCentralSurfaces.executeRunnableDismissingKeyguard( - () -> mKeyguardBottomArea.launchLeftAffordance(), null, - true /* dismissShade */, false /* afterKeyguardGone */, - true /* deferred */); - } else { - mKeyguardBottomArea.launchLeftAffordance(); - } - } else { - if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals( - mLastCameraLaunchSource)) { - mLockscreenGestureLogger.write( - MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp); - mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA); - } - mFalsingCollector.onCameraOn(); - if (mFalsingCollector.shouldEnforceBouncer()) { - mCentralSurfaces.executeRunnableDismissingKeyguard( - () -> mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource), null, - true /* dismissShade */, false /* afterKeyguardGone */, - true /* deferred */); - } else { - mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); - } - } - mCentralSurfaces.startLaunchTransitionTimeout(); - mBlockTouches = true; - } - - @Override - public void onAnimationToSideEnded() { - mIsLaunchTransitionRunning = false; - mIsLaunchTransitionFinished = true; - if (mLaunchAnimationEndRunnable != null) { - mLaunchAnimationEndRunnable.run(); - mLaunchAnimationEndRunnable = null; - } - mCentralSurfaces.readyForKeyguardDone(); - } - - @Override - public float getMaxTranslationDistance() { - return (float) Math.hypot(mView.getWidth(), getHeight()); - } - - @Override - public void onSwipingStarted(boolean rightIcon) { - mFalsingCollector.onAffordanceSwipingStarted(rightIcon); - mView.requestDisallowInterceptTouchEvent(true); - mOnlyAffordanceInThisMotion = true; - mQsTracking = false; - } - - @Override - public void onSwipingAborted() { - mFalsingCollector.onAffordanceSwipingAborted(); - } - - @Override - public void onIconClicked(boolean rightIcon) { - if (mHintAnimationRunning) { - return; - } - mHintAnimationRunning = true; - mAffordanceHelper.startHintAnimation(rightIcon, () -> { - mHintAnimationRunning = false; - mCentralSurfaces.onHintFinished(); - }); - rightIcon = - mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? !rightIcon - : rightIcon; - if (rightIcon) { - mCentralSurfaces.onCameraHintStarted(); - } else { - if (mKeyguardBottomArea.isLeftVoiceAssist()) { - mCentralSurfaces.onVoiceAssistHintStarted(); - } else { - mCentralSurfaces.onPhoneHintStarted(); - } - } - } - - @Override - public KeyguardAffordanceView getLeftIcon() { - return mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getRightView() : mKeyguardBottomArea.getLeftView(); - } - - @Override - public KeyguardAffordanceView getRightIcon() { - return mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getLeftView() : mKeyguardBottomArea.getRightView(); - } - - @Override - public View getLeftPreview() { - return mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getRightPreview() : mKeyguardBottomArea.getLeftPreview(); - } - - @Override - public View getRightPreview() { - return mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getLeftPreview() : mKeyguardBottomArea.getRightPreview(); - } - - @Override - public float getAffordanceFalsingFactor() { - return mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f; - } - - @Override - public boolean needsAntiFalsing() { - return mBarState == KEYGUARD; - } - } - private class OnEmptySpaceClickListener implements NotificationStackScrollLayout.OnEmptySpaceClickListener { @Override @@ -5104,15 +4877,6 @@ public class NotificationPanelViewController extends PanelViewController { } } - private class OnConfigurationChangedListener extends - PanelViewController.OnConfigurationChangedListener { - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mAffordanceHelper.onConfigurationChanged(); - } - } - private class OnApplyWindowInsetsListener implements View.OnApplyWindowInsetsListener { public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { // the same types of insets that are handled in NotificationShadeWindowView diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS index 18f0fb38999c..f5828f914eab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/OWNERS @@ -1,3 +1,16 @@ per-file *Notification* = set noparent per-file *Notification* = file:../notification/OWNERS -per-file NotificationIcon* = ccassidy@google.com, evanlaird@google.com, pixel@google.com
\ No newline at end of file + +per-file NotificationIcon* = ccassidy@google.com, evanlaird@google.com, pixel@google.com + +per-file NotificationsQuickSettingsContainer.java = kozynski@google.com, asc@google.com +per-file NotificationsQSContainerController.kt = kozynski@google.com, asc@google.com + +per-file NotificationShadeWindowControllerImpl.java = dupin@google.com, cinek@google.com, beverlyt@google.com, pixel@google.com, juliacr@google.com +per-file NotificationShadeWindowViewController.java = pixel@google.com, cinek@google.com, juliacr@google.com +per-file NotificationShadeWindowView.java = pixel@google.com, cinek@google.com, juliacr@google.com + +per-file NotificationPanelUnfoldAnimationController.kt = alexflo@google.com, jeffdq@google.com, juliacr@google.com + +per-file NotificationPanelView.java = pixel@google.com, cinek@google.com, juliacr@google.com +per-file NotificationPanelViewController.java = pixel@google.com, cinek@google.com, juliacr@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index ed12b00cc644..d2fc1af010b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -484,8 +484,6 @@ public abstract class PanelViewController { protected abstract boolean shouldGestureWaitForTouchSlop(); - protected abstract boolean shouldGestureIgnoreXTouchSlop(float x, float y); - protected void onTrackingStopped(boolean expand) { mTracking = false; mCentralSurfaces.onTrackingStopped(expand); @@ -1333,7 +1331,7 @@ public abstract class PanelViewController { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop(); - mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y); + mIgnoreXTouchSlop = true; } switch (event.getActionMasked()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index a89c128dd584..753e94015751 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -119,6 +119,17 @@ public interface BatteryController extends DemoMode, Dumpable, } /** + * Returns {@code true} if the charging source is + * {@link android.os.BatteryManager#BATTERY_PLUGGED_DOCK}. + * + * <P>Note that charging from dock is not considered as wireless charging. In other words, + * {@link BatteryController#isWirelessCharging()} and this are mutually exclusive. + */ + default boolean isChargingSourceDock() { + return false; + } + + /** * A listener that will be notified whenever a change in battery level or power save mode has * occurred. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 917a5e0b9374..33ddf7eed006 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -76,7 +76,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC protected int mLevel; protected boolean mPluggedIn; - private boolean mPluggedInWireless; + private int mPluggedChargingSource; protected boolean mCharging; private boolean mStateUnknown = false; private boolean mCharged; @@ -195,10 +195,8 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC mLevel = (int)(100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); - mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; - mPluggedInWireless = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) - == BatteryManager.BATTERY_PLUGGED_WIRELESS; - + mPluggedChargingSource = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + mPluggedIn = mPluggedChargingSource != 0; final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); mCharged = status == BatteryManager.BATTERY_STATUS_FULL; @@ -284,7 +282,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Override public boolean isPluggedInWireless() { - return mPluggedInWireless; + return mPluggedChargingSource == BatteryManager.BATTERY_PLUGGED_WIRELESS; } @Override @@ -441,4 +439,9 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC registerReceiver(); updatePowerSave(); } + + @Override + public boolean isChargingSourceDock() { + return mPluggedChargingSource == BatteryManager.BATTERY_PLUGGED_DOCK; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java deleted file mode 100644 index 3d317143eb51..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.policy; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; - -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.ActivityIntentHelper; -import com.android.systemui.statusbar.phone.KeyguardPreviewContainer; - -import java.util.List; - -/** - * Utility class to inflate previews for phone and camera affordance. - */ -public class PreviewInflater { - - private static final String TAG = "PreviewInflater"; - - private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout"; - private final ActivityIntentHelper mActivityIntentHelper; - - private Context mContext; - private LockPatternUtils mLockPatternUtils; - - public PreviewInflater(Context context, LockPatternUtils lockPatternUtils, - ActivityIntentHelper activityIntentHelper) { - mContext = context; - mLockPatternUtils = lockPatternUtils; - mActivityIntentHelper = activityIntentHelper; - } - - public View inflatePreview(Intent intent) { - WidgetInfo info = getWidgetInfo(intent); - return inflatePreview(info); - } - - public View inflatePreviewFromService(ComponentName componentName) { - WidgetInfo info = getWidgetInfoFromService(componentName); - return inflatePreview(info); - } - - private KeyguardPreviewContainer inflatePreview(WidgetInfo info) { - if (info == null) { - return null; - } - View v = inflateWidgetView(info); - if (v == null) { - return null; - } - KeyguardPreviewContainer container = new KeyguardPreviewContainer(mContext, null); - container.addView(v); - return container; - } - - private View inflateWidgetView(WidgetInfo widgetInfo) { - View widgetView = null; - try { - Context appContext = mContext.createPackageContext( - widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED); - LayoutInflater appInflater = (LayoutInflater) - appContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - appInflater = appInflater.cloneInContext(appContext); - widgetView = appInflater.inflate(widgetInfo.layoutId, null, false); - } catch (PackageManager.NameNotFoundException|RuntimeException e) { - Log.w(TAG, "Error creating widget view", e); - } - return widgetView; - } - - private WidgetInfo getWidgetInfoFromService(ComponentName componentName) { - PackageManager packageManager = mContext.getPackageManager(); - // Look for the preview specified in the service meta-data - try { - Bundle metaData = packageManager.getServiceInfo( - componentName, PackageManager.GET_META_DATA).metaData; - return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString() - + " not found", e); - } - return null; - } - - private WidgetInfo getWidgetInfoFromMetaData(String contextPackage, - Bundle metaData) { - if (metaData == null) { - return null; - } - int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT); - if (layoutId == 0) { - return null; - } - WidgetInfo info = new WidgetInfo(); - info.contextPackage = contextPackage; - info.layoutId = layoutId; - return info; - } - - private WidgetInfo getWidgetInfo(Intent intent) { - PackageManager packageManager = mContext.getPackageManager(); - int flags = PackageManager.MATCH_DEFAULT_ONLY - | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; - final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, flags, KeyguardUpdateMonitor.getCurrentUser()); - if (appList.size() == 0) { - return null; - } - ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, - flags | PackageManager.GET_META_DATA, - KeyguardUpdateMonitor.getCurrentUser()); - if (mActivityIntentHelper.wouldLaunchResolverActivity(resolved, appList)) { - return null; - } - if (resolved == null || resolved.activityInfo == null) { - return null; - } - return getWidgetInfoFromMetaData(resolved.activityInfo.packageName, - resolved.activityInfo.metaData); - } - - private static class WidgetInfo { - String contextPackage; - int layoutId; - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 0fdd9054e4bc..b61bda8edd10 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -468,6 +469,40 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { verify(mView).setUnpausedAlpha(255); } + @Test + public void testUpdatePanelExpansion_pauseAuth() { + // GIVEN view is attached + on the keyguard + mController.onViewAttached(); + captureStatusBarStateListeners(); + captureStatusBarExpansionListeners(); + sendStatusBarStateChanged(StatusBarState.KEYGUARD); + reset(mView); + + // WHEN panelViewExpansion changes to hide + when(mView.getUnpausedAlpha()).thenReturn(0); + updateStatusBarExpansion(0f, false); + + // THEN pause auth is updated to PAUSE + verify(mView, atLeastOnce()).setPauseAuth(true); + } + + @Test + public void testUpdatePanelExpansion_unpauseAuth() { + // GIVEN view is attached + on the keyguard + panel expansion is 0f + mController.onViewAttached(); + captureStatusBarStateListeners(); + captureStatusBarExpansionListeners(); + sendStatusBarStateChanged(StatusBarState.KEYGUARD); + reset(mView); + + // WHEN panelViewExpansion changes to expanded + when(mView.getUnpausedAlpha()).thenReturn(255); + updateStatusBarExpansion(1f, true); + + // THEN pause auth is updated to NOT pause + verify(mView, atLeastOnce()).setPauseAuth(false); + } + private void sendStatusBarStateChanged(int statusBarState) { mStatusBarStateListener.onStateChanged(statusBarState); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt index b4cae38d8b6e..d0cf792b698d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt @@ -74,9 +74,9 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { // Verify ripple added to window manager. captor.value.onBatteryLevelChanged( - 0 /* unusedBatteryLevel */, - true /* plugged in */, - false /* charging */) + /* unusedBatteryLevel= */ 0, + /* plugged in= */ true, + /* charging= */ false) val attachListenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java) verify(rippleView).addOnAttachStateChangeListener(attachListenerCaptor.capture()) @@ -144,4 +144,22 @@ class WiredChargingRippleControllerTest : SysuiTestCase() { // Verify that ripple is triggered. verify(rippleView).addOnAttachStateChangeListener(ArgumentMatchers.any()) } + + @Test + fun testRipple_whenDocked_doesNotPlayRipple() { + `when`(batteryController.isChargingSourceDock).thenReturn(true) + val captor = ArgumentCaptor + .forClass(BatteryController.BatteryStateChangeCallback::class.java) + verify(batteryController).addCallback(captor.capture()) + + captor.value.onBatteryLevelChanged( + /* unusedBatteryLevel= */ 0, + /* plugged in= */ true, + /* charging= */ false) + + val attachListenerCaptor = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java) + verify(rippleView, never()).addOnAttachStateChangeListener(attachListenerCaptor.capture()) + verify(windowManager, never()).addView(eq(rippleView), any<WindowManager.LayoutParams>()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java index 769143ddbc0d..d4add7547656 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java @@ -108,6 +108,7 @@ public class NotificationEntryTest extends SysuiTestCase { @Test public void testBlockableEntryWhenCritical() { doReturn(true).when(mChannel).isBlockable(); + mEntry.setRanking(mEntry.getRanking()); assertTrue(mEntry.isBlockable()); } @@ -117,6 +118,7 @@ public class NotificationEntryTest extends SysuiTestCase { public void testBlockableEntryWhenCriticalAndChannelNotBlockable() { doReturn(true).when(mChannel).isBlockable(); doReturn(true).when(mChannel).isImportanceLockedByCriticalDeviceFunction(); + mEntry.setRanking(mEntry.getRanking()); assertTrue(mEntry.isBlockable()); } @@ -125,6 +127,7 @@ public class NotificationEntryTest extends SysuiTestCase { public void testNonBlockableEntryWhenCriticalAndChannelNotBlockable() { doReturn(false).when(mChannel).isBlockable(); doReturn(true).when(mChannel).isImportanceLockedByCriticalDeviceFunction(); + mEntry.setRanking(mEntry.getRanking()); assertFalse(mEntry.isBlockable()); } @@ -164,6 +167,9 @@ public class NotificationEntryTest extends SysuiTestCase { doReturn(true).when(mChannel).isImportanceLockedByCriticalDeviceFunction(); doReturn(false).when(mChannel).isBlockable(); + mEntry.setRanking(mEntry.getRanking()); + + assertFalse(mEntry.isBlockable()); assertTrue(mEntry.isExemptFromDndVisualSuppression()); assertFalse(mEntry.shouldSuppressAmbient()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 2faff0ced70a..266f0e95f2ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -848,7 +848,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCentralSurfaces.showKeyguardImpl(); // Starting a pulse should change the scrim controller to the pulsing state - when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true); when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(true); mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any()); @@ -885,7 +884,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCentralSurfaces.showKeyguardImpl(); // Starting a pulse should change the scrim controller to the pulsing state - when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true); when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(false); mCentralSurfaces.updateScrimController(); verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt index 31465f45af42..4b557dc423ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt @@ -12,12 +12,12 @@ import com.android.systemui.statusbar.policy.AccessibilityController import com.android.systemui.statusbar.policy.FlashlightController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.tuner.TunerService +import java.util.concurrent.Executor import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations -import java.util.concurrent.Executor @SmallTest @RunWith(AndroidTestingRunner::class) @@ -51,6 +51,5 @@ class KeyguardBottomAreaTest : SysuiTestCase() { null, false) as KeyguardBottomAreaView other.initFrom(mKeyguardBottomArea) - other.launchVoiceAssist() } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 823a986af5a9..cec6a81f8733 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -106,7 +106,6 @@ import com.android.systemui.plugins.qs.QS; import com.android.systemui.qrcodescanner.controller.QRCodeScannerController; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -404,8 +403,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { .thenReturn(mHeadsUpCallback); when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); - when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class)); - when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class)); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); when(mView.findViewById(R.id.keyguard_status_view)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java index fec2123b304a..fda80a2f9ed8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Intent; +import android.os.BatteryManager; import android.os.Handler; import android.os.PowerManager; import android.os.PowerSaveState; @@ -196,4 +197,26 @@ public class BatteryControllerTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); // Should not throw an exception } + + @Test + public void batteryStateChanged_withChargingSourceDock_isChargingSourceDockTrue() { + Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); + intent.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING); + intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_DOCK); + + mBatteryController.onReceive(getContext(), intent); + + Assert.assertTrue(mBatteryController.isChargingSourceDock()); + } + + @Test + public void batteryStateChanged_withChargingSourceNotDock_isChargingSourceDockFalse() { + Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); + intent.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_DISCHARGING); + intent.putExtra(BatteryManager.EXTRA_PLUGGED, BatteryManager.BATTERY_PLUGGED_WIRELESS); + + mBatteryController.onReceive(getContext(), intent); + + Assert.assertFalse(mBatteryController.isChargingSourceDock()); + } } diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index ab9966f218c1..c7bd3a7c18aa 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -76,6 +76,7 @@ import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.Parcel; +import android.os.ParcelFileDescriptor; import android.os.PowerWhitelistManager; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -727,6 +728,19 @@ public class CompanionDeviceManagerService extends SystemService { } @Override + public void attachSystemDataTransport(String packageName, int userId, int associationId, + ParcelFileDescriptor fd) { + mSystemDataTransferProcessor.attachSystemDataTransport(packageName, userId, + associationId, fd); + } + + @Override + public void detachSystemDataTransport(String packageName, int userId, int associationId) { + mSystemDataTransferProcessor.detachSystemDataTransport(packageName, userId, + associationId); + } + + @Override public void notifyDeviceAppeared(int associationId) { if (DEBUG) Log.i(TAG, "notifyDevice_Appeared() id=" + associationId); diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 70745ba0b368..a839492dd7ac 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -37,16 +37,26 @@ import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.Handler; +import android.os.ParcelFileDescriptor; import android.os.ResultReceiver; import android.os.UserHandle; import android.permission.PermissionControllerManager; import android.util.Slog; +import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.server.companion.AssociationStore; import com.android.server.companion.CompanionDeviceManagerService; import com.android.server.companion.PermissionsUtils; import com.android.server.companion.proto.CompanionMessage; +import libcore.io.IoUtils; +import libcore.io.Streams; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -77,6 +87,8 @@ public class SystemDataTransferProcessor { private final CompanionMessageProcessor mCompanionMessageProcessor; private final PermissionControllerManager mPermissionControllerManager; private final ExecutorService mExecutor; + @GuardedBy("mTransports") + private final SparseArray<Transport> mTransports = new SparseArray<>(); public SystemDataTransferProcessor(CompanionDeviceManagerService service, AssociationStore associationStore, @@ -92,10 +104,11 @@ public class SystemDataTransferProcessor { } /** - * Build a PendingIntent of permission sync user consent dialog + * Resolve the requested association, throwing if the caller doesn't have + * adequate permissions. */ - public PendingIntent buildPermissionTransferUserConsentIntent(String packageName, - @UserIdInt int userId, int associationId) { + private @NonNull AssociationInfo resolveAssociation(String packageName, int userId, + int associationId) { AssociationInfo association = mAssociationStore.getAssociationById(associationId); association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association); if (association == null) { @@ -103,6 +116,15 @@ public class SystemDataTransferProcessor { + associationId + " is not associated with the app " + packageName + " for user " + userId); } + return association; + } + + /** + * Build a PendingIntent of permission sync user consent dialog + */ + public PendingIntent buildPermissionTransferUserConsentIntent(String packageName, + @UserIdInt int userId, int associationId) { + final AssociationInfo association = resolveAssociation(packageName, userId, associationId); // Check if the request's data type has been requested before. List<SystemDataTransferRequest> storedRequests = @@ -150,13 +172,7 @@ public class SystemDataTransferProcessor { Slog.i(LOG_TAG, "Start system data transfer for package [" + packageName + "] userId [" + userId + "] associationId [" + associationId + "]"); - AssociationInfo association = mAssociationStore.getAssociationById(associationId); - association = PermissionsUtils.sanitizeWithCallerChecks(mContext, association); - if (association == null) { - throw new DeviceNotAssociatedException("Association " - + associationId + " is not associated with the app " + packageName - + " for user " + userId); - } + final AssociationInfo association = resolveAssociation(packageName, userId, associationId); // Check if the request has been consented by the user. List<SystemDataTransferRequest> storedRequests = @@ -188,6 +204,35 @@ public class SystemDataTransferProcessor { } } + public void attachSystemDataTransport(String packageName, int userId, int associationId, + ParcelFileDescriptor fd) { + synchronized (mTransports) { + // TODO: restore once testing has evolved + // resolveAssociation(packageName, userId, associationId); + + if (mTransports.contains(associationId)) { + detachSystemDataTransport(packageName, userId, associationId); + } + + final Transport transport = new Transport(fd); + transport.start(); + mTransports.put(associationId, transport); + } + } + + public void detachSystemDataTransport(String packageName, int userId, int associationId) { + synchronized (mTransports) { + // TODO: restore once testing has evolved + // resolveAssociation(packageName, userId, associationId); + + final Transport transport = mTransports.get(associationId); + if (transport != null) { + mTransports.delete(associationId); + transport.stop(); + } + } + } + /** * Process a complete decrypted message reported by the companion app. */ @@ -242,4 +287,74 @@ public class SystemDataTransferProcessor { Slog.e(LOG_TAG, "Unknown result code:" + resultCode); } }; + + private class Transport { + private final InputStream mRemoteIn; + private final OutputStream mRemoteOut; + + private volatile boolean mStopped; + + public Transport(ParcelFileDescriptor fd) { + mRemoteIn = new ParcelFileDescriptor.AutoCloseInputStream(fd); + mRemoteOut = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + } + + public void start() { + new Thread(() -> { + try { + while (!mStopped) { + processNextCommand(); + } + } catch (IOException e) { + if (!mStopped) { + Slog.w(LOG_TAG, "Trouble during transport", e); + stop(); + } + } + }).start(); + } + + public void stop() { + mStopped = true; + + IoUtils.closeQuietly(mRemoteIn); + IoUtils.closeQuietly(mRemoteOut); + } + + private void processNextCommand() throws IOException { + Slog.d(LOG_TAG, "Waiting for next command..."); + + // Read message header + final byte[] headerBytes = new byte[8]; + Streams.readFully(mRemoteIn, headerBytes); + final ByteBuffer header = ByteBuffer.wrap(headerBytes); + final int command = header.getInt(); + final int length = header.getInt(); + + Slog.d(LOG_TAG, "Received command 0x" + Integer.toHexString(command) + + " length " + length); + switch (command) { + case 0x50490000: // PI(NG) version 0 + // Repeat back the given payload, within reason + final int target = Math.min(length, 1_000_000); + final byte[] payload = new byte[target]; + Streams.readFully(mRemoteIn, payload); + Streams.skipByReading(mRemoteIn, length - target); + + // Respond with PO(NG) version 0 + header.rewind(); + header.putInt(0x504F0000); + header.putInt(target); + mRemoteOut.write(header.array()); + mRemoteOut.write(payload); + break; + + default: + // Emit local warning, and skip message to + // handle next one + Slog.w(LOG_TAG, "Unknown command 0x" + Integer.toHexString(command)); + mRemoteIn.skip(length); + } + } + } } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index bddc784385e7..a23870567cdb 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -56,7 +56,6 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Parcel; -import android.os.ParcelFileDescriptor; import android.os.ParcelFormatException; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; @@ -728,56 +727,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub return mBatteryUsageStatsProvider.getBatteryUsageStats(queries); } - @Override - @EnforcePermission(BATTERY_STATS) - public byte[] getStatistics() { - //Slog.i("foo", "SENDING BATTERY INFO:"); - //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); - Parcel out = Parcel.obtain(); - // Drain the handler queue to make sure we've handled all pending works, so we'll get - // an accurate stats. - awaitCompletion(); - syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL); - synchronized (mStats) { - mStats.writeToParcel(out, 0); - } - byte[] data = out.marshall(); - out.recycle(); - return data; - } - - /** - * Returns parceled BatteryStats as a MemoryFile. - * - * @param forceUpdate If true, runs a sync to get fresh battery stats. Otherwise, - * returns the current values. - */ - @Override - @EnforcePermission(BATTERY_STATS) - public ParcelFileDescriptor getStatisticsStream(boolean forceUpdate) { - //Slog.i("foo", "SENDING BATTERY INFO:"); - //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM)); - Parcel out = Parcel.obtain(); - if (forceUpdate) { - // Drain the handler queue to make sure we've handled all pending works, so we'll get - // an accurate stats. - awaitCompletion(); - syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL); - } - synchronized (mStats) { - mStats.writeToParcel(out, 0); - } - byte[] data = out.marshall(); - if (DBG) Slog.d(TAG, "getStatisticsStream parcel size is:" + data.length); - out.recycle(); - try { - return ParcelFileDescriptor.fromData(data, "battery-stats"); - } catch (IOException e) { - Slog.w(TAG, "Unable to create shared memory", e); - return null; - } - } - /** Register callbacks for statsd pulled atoms. */ private void registerStatsCallbacks() { final StatsManager statsManager = mContext.getSystemService(StatsManager.class); diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 453385938aca..4ff1a129f691 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -29,6 +29,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerService.TAG_MU; import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PROVIDER; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -48,7 +49,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.content.pm.UserInfo; @@ -958,20 +958,22 @@ public class ContentProviderHelper { String getProviderMimeType(Uri uri, int userId) { mService.enforceNotIsolatedCaller("getProviderMimeType"); final String name = uri.getAuthority(); - int callingUid = Binder.getCallingUid(); - int callingPid = Binder.getCallingPid(); - long ident = 0; - boolean clearedIdentity = false; - userId = mService.mUserController.unsafeConvertIncomingUser(userId); - if (canClearIdentity(callingPid, callingUid, userId)) { - clearedIdentity = true; - ident = Binder.clearCallingIdentity(); - } - ContentProviderHolder holder = null; + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId); + final long ident = canClearIdentity(callingPid, callingUid, safeUserId) + ? Binder.clearCallingIdentity() : 0; + final ContentProviderHolder holder; try { holder = getContentProviderExternalUnchecked(name, null, callingUid, - "*getmimetype*", userId); - if (holder != null) { + "*getmimetype*", safeUserId); + } finally { + if (ident != 0) { + Binder.restoreCallingIdentity(ident); + } + } + try { + if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) { final IBinder providerConnection = holder.connection; final ComponentName providerName = holder.info.getComponentName(); // Note: creating a new Runnable instead of using a lambda here since lambdas in @@ -1000,15 +1002,13 @@ public class ContentProviderHelper { return null; } finally { // We need to clear the identity to call removeContentProviderExternalUnchecked - if (!clearedIdentity) { - ident = Binder.clearCallingIdentity(); - } + final long token = Binder.clearCallingIdentity(); try { if (holder != null) { - removeContentProviderExternalUnchecked(name, null, userId); + removeContentProviderExternalUnchecked(name, null /* token */, safeUserId); } } finally { - Binder.restoreCallingIdentity(ident); + Binder.restoreCallingIdentity(token); } } @@ -1027,12 +1027,20 @@ public class ContentProviderHelper { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId); - final long ident = canClearIdentity(callingPid, callingUid, userId) + final long ident = canClearIdentity(callingPid, callingUid, safeUserId) ? Binder.clearCallingIdentity() : 0; + final ContentProviderHolder holder; try { - final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null, + holder = getContentProviderExternalUnchecked(name, null /* token */, callingUid, "*getmimetype*", safeUserId); - if (holder != null) { + } finally { + if (ident != 0) { + Binder.restoreCallingIdentity(ident); + } + } + + try { + if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) { holder.provider.getTypeAsync(uri, new RemoteCallback(result -> { final long identity = Binder.clearCallingIdentity(); try { @@ -1048,8 +1056,6 @@ public class ContentProviderHelper { } catch (RemoteException e) { Log.w(TAG, "Content provider dead retrieving " + uri, e); resultCallback.sendResult(Bundle.EMPTY); - } finally { - Binder.restoreCallingIdentity(ident); } } @@ -1065,6 +1071,16 @@ public class ContentProviderHelper { callingUid, -1, true) == PackageManager.PERMISSION_GRANTED; } + private boolean isHolderVisibleToCaller(@Nullable ContentProviderHolder holder, int callingUid, + @UserIdInt int userId) { + if (holder == null || holder.info == null) { + return false; + } + + return !mService.getPackageManagerInternal() + .filterAppAccess(holder.info.packageName, callingUid, userId); + } + /** * Check if the calling UID has a possible chance at accessing the provider * at the given authority and user. @@ -1133,9 +1149,7 @@ public class ContentProviderHelper { "*checkContentProviderUriPermission*", userId); if (holder != null) { - final PackageManagerInternal packageManagerInt = LocalServices.getService( - PackageManagerInternal.class); - final AndroidPackage androidPackage = packageManagerInt + final AndroidPackage androidPackage = mService.getPackageManagerInternal() .getPackage(Binder.getCallingUid()); if (androidPackage == null) { return PackageManager.PERMISSION_DENIED; diff --git a/services/core/java/com/android/server/broadcastradio/OWNERS b/services/core/java/com/android/server/broadcastradio/OWNERS index 3e360e7e992c..d2bdd643b0a2 100644 --- a/services/core/java/com/android/server/broadcastradio/OWNERS +++ b/services/core/java/com/android/server/broadcastradio/OWNERS @@ -1,3 +1,3 @@ -keunyoung@google.com +xuweilin@google.com oscarazu@google.com -twasilczyk@google.com +keunyoung@google.com diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 845e932cdff9..5b282ced73b5 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -3301,8 +3301,13 @@ public class Vpn { cancelHandleNetworkLostTimeout(); synchronized (Vpn.this) { + String category = null; + int errorClass = -1; + int errorCode = -1; if (exception instanceof IkeProtocolException) { final IkeProtocolException ikeException = (IkeProtocolException) exception; + category = VpnManager.CATEGORY_EVENT_IKE_ERROR; + errorCode = ikeException.getErrorType(); switch (ikeException.getErrorType()) { case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough @@ -3312,105 +3317,53 @@ public class Vpn { case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE: // All the above failures are configuration errors, and are terminal - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR, - VpnManager.ERROR_CLASS_NOT_RECOVERABLE, - ikeException.getErrorType(), - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } - markFailedAndDisconnect(exception); - return; + errorClass = VpnManager.ERROR_CLASS_NOT_RECOVERABLE; + break; // All other cases possibly recoverable. default: // All the above failures are configuration errors, and are terminal - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_IKE_ERROR, - VpnManager.ERROR_CLASS_RECOVERABLE, - ikeException.getErrorType(), - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } + errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; } } else if (exception instanceof IllegalArgumentException) { // Failed to build IKE/ChildSessionParams; fatal profile configuration error markFailedAndDisconnect(exception); return; } else if (exception instanceof IkeNetworkLostException) { - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR, - VpnManager.ERROR_CLASS_RECOVERABLE, - VpnManager.ERROR_CODE_NETWORK_LOST, - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } + category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR; + errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; + errorCode = VpnManager.ERROR_CODE_NETWORK_LOST; } else if (exception instanceof IkeNonProtocolException) { + category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR; + errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; if (exception.getCause() instanceof UnknownHostException) { - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR, - VpnManager.ERROR_CLASS_RECOVERABLE, - VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST, - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } + errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST; } else if (exception.getCause() instanceof IkeTimeoutException) { - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR, - VpnManager.ERROR_CLASS_RECOVERABLE, - VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT, - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } + errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT; } else if (exception.getCause() instanceof IOException) { - // TODO(b/230548427): Remove SDK check once VPN related stuff are - // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT()) { - sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_NETWORK_ERROR, - VpnManager.ERROR_CLASS_RECOVERABLE, - VpnManager.ERROR_CODE_NETWORK_IO, - getPackage(), mSessionKey, makeVpnProfileStateLocked(), - network, - getRedactedNetworkCapabilitiesOfUnderlyingNetwork( - mUnderlyingNetworkCapabilities), - getRedactedLinkPropertiesOfUnderlyingNetwork( - mUnderlyingLinkProperties)); - } + errorCode = VpnManager.ERROR_CODE_NETWORK_IO; } } else if (exception != null) { Log.wtf(TAG, "onSessionLost: exception = " + exception); } - scheduleRetryNewIkeSession(); + // TODO(b/230548427): Remove SDK check once VPN related stuff are + // decoupled from ConnectivityServiceTest. + if (SdkLevel.isAtLeastT() && category != null) { + sendEventToVpnManagerApp(category, errorClass, errorCode, + getPackage(), mSessionKey, makeVpnProfileStateLocked(), + mActiveNetwork, + getRedactedNetworkCapabilitiesOfUnderlyingNetwork( + mUnderlyingNetworkCapabilities), + getRedactedLinkPropertiesOfUnderlyingNetwork( + mUnderlyingLinkProperties)); + } + + if (errorClass == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) { + markFailedAndDisconnect(exception); + return; + } else { + scheduleRetryNewIkeSession(); + } } mUnderlyingNetworkCapabilities = null; diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 5a8190a833e3..3fceba77567b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2476,7 +2476,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // We don't start input when session for a11y is created. We start input when // input method start input, a11y manager service is always on. if (startInputReason != StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY) { - final Binder startInputToken = new Binder(); setEnabledSessionForAccessibilityLocked(mCurClient.mAccessibilitySessions); AccessibilityManagerInternal.get().startInput(mCurRemoteAccessibilityInputConnection, mCurEditorInfo, !initial /* restarting */); diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index 1235352b0590..549fd4918023 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -2523,10 +2523,16 @@ public class LocationProviderManager extends filtered = locationResult; } - Location last = getLastLocationUnsafe(USER_CURRENT, PERMISSION_FINE, true, Long.MAX_VALUE); - if (last != null && locationResult.get(0).getElapsedRealtimeNanos() - < last.getElapsedRealtimeNanos()) { - Log.e(TAG, "non-monotonic location received from " + mName + " provider"); + // check for non-monotonic locations if we're not the passive manager. the passive manager + // is much more likely to see non-monotonic locations since it gets locations from all + // providers, so this error log is not very useful there. + if (mPassiveManager != null) { + Location last = getLastLocationUnsafe(USER_CURRENT, PERMISSION_FINE, true, + Long.MAX_VALUE); + if (last != null && locationResult.get(0).getElapsedRealtimeNanos() + < last.getElapsedRealtimeNanos()) { + Log.e(TAG, "non-monotonic location received from " + mName + " provider"); + } } // update last location diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 24bd42e7d775..3edbfe038ce6 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -122,9 +122,9 @@ public class SyntheticPasswordManager { // 256-bit synthetic password private static final byte SYNTHETIC_PASSWORD_LENGTH = 256 / 8; - private static final int PASSWORD_SCRYPT_N = 11; - private static final int PASSWORD_SCRYPT_R = 3; - private static final int PASSWORD_SCRYPT_P = 1; + private static final int PASSWORD_SCRYPT_LOG_N = 11; + private static final int PASSWORD_SCRYPT_LOG_R = 3; + private static final int PASSWORD_SCRYPT_LOG_P = 1; private static final int PASSWORD_SALT_LENGTH = 16; private static final int PASSWORD_TOKEN_LENGTH = 32; private static final String TAG = "SyntheticPasswordManager"; @@ -192,7 +192,11 @@ public class SyntheticPasswordManager { mVersion = version; } - private byte[] derivePassword(byte[] personalization) { + /** + * Derives a subkey from the synthetic password. For v3 and later synthetic passwords the + * subkeys are 256-bit; for v1 and v2 they are 512-bit. + */ + private byte[] deriveSubkey(byte[] personalization) { if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) { return (new SP800Derive(mSyntheticPassword)) .withContext(personalization, PERSONALISATION_CONTEXT); @@ -203,28 +207,28 @@ public class SyntheticPasswordManager { } public byte[] deriveKeyStorePassword() { - return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); + return bytesToHex(deriveSubkey(PERSONALIZATION_KEY_STORE_PASSWORD)); } public byte[] deriveGkPassword() { - return derivePassword(PERSONALIZATION_SP_GK_AUTH); + return deriveSubkey(PERSONALIZATION_SP_GK_AUTH); } public byte[] deriveDiskEncryptionKey() { - return derivePassword(PERSONALIZATION_FBE_KEY); + return deriveSubkey(PERSONALIZATION_FBE_KEY); } public byte[] deriveVendorAuthSecret() { - return derivePassword(PERSONALIZATION_AUTHSECRET_KEY); + return deriveSubkey(PERSONALIZATION_AUTHSECRET_KEY); } public byte[] derivePasswordHashFactor() { - return derivePassword(PERSONALIZATION_PASSWORD_HASH); + return deriveSubkey(PERSONALIZATION_PASSWORD_HASH); } /** Derives key used to encrypt password metrics */ public byte[] deriveMetricsKey() { - return derivePassword(PERSONALIZATION_PASSWORD_METRICS); + return deriveSubkey(PERSONALIZATION_PASSWORD_METRICS); } /** @@ -274,9 +278,8 @@ public class SyntheticPasswordManager { * AuthenticationToken.mSyntheticPassword for details on what each block means. */ private void recreate(byte[] escrowSplit0, byte[] escrowSplit1) { - mSyntheticPassword = String.valueOf(HexEncoding.encode( - SyntheticPasswordCrypto.personalisedHash( - PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1))).getBytes(); + mSyntheticPassword = bytesToHex(SyntheticPasswordCrypto.personalisedHash( + PERSONALIZATION_SP_SPLIT, escrowSplit0, escrowSplit1)); } /** @@ -310,9 +313,9 @@ public class SyntheticPasswordManager { } static class PasswordData { - byte scryptN; - byte scryptR; - byte scryptP; + byte scryptLogN; + byte scryptLogR; + byte scryptLogP; public int credentialType; byte[] salt; // For GateKeeper-based credential, this is the password handle returned by GK, @@ -321,9 +324,9 @@ public class SyntheticPasswordManager { public static PasswordData create(int passwordType) { PasswordData result = new PasswordData(); - result.scryptN = PASSWORD_SCRYPT_N; - result.scryptR = PASSWORD_SCRYPT_R; - result.scryptP = PASSWORD_SCRYPT_P; + result.scryptLogN = PASSWORD_SCRYPT_LOG_N; + result.scryptLogR = PASSWORD_SCRYPT_LOG_R; + result.scryptLogP = PASSWORD_SCRYPT_LOG_P; result.credentialType = passwordType; result.salt = secureRandom(PASSWORD_SALT_LENGTH); return result; @@ -335,9 +338,9 @@ public class SyntheticPasswordManager { buffer.put(data, 0, data.length); buffer.flip(); result.credentialType = buffer.getInt(); - result.scryptN = buffer.get(); - result.scryptR = buffer.get(); - result.scryptP = buffer.get(); + result.scryptLogN = buffer.get(); + result.scryptLogR = buffer.get(); + result.scryptLogP = buffer.get(); int saltLen = buffer.getInt(); result.salt = new byte[saltLen]; buffer.get(result.salt); @@ -357,9 +360,9 @@ public class SyntheticPasswordManager { + Integer.BYTES + salt.length + Integer.BYTES + (passwordHandle != null ? passwordHandle.length : 0)); buffer.putInt(credentialType); - buffer.put(scryptN); - buffer.put(scryptR); - buffer.put(scryptP); + buffer.put(scryptLogN); + buffer.put(scryptLogR); + buffer.put(scryptLogP); buffer.putInt(salt.length); buffer.put(salt); if (passwordHandle != null && passwordHandle.length > 0) { @@ -930,26 +933,6 @@ public class SyntheticPasswordManager { private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>(); /** - * Create a token based Synthetic password for the given user. - * @return the handle of the token - */ - public long createStrongTokenBasedSyntheticPassword(byte[] token, int userId, - @Nullable EscrowTokenStateChangeCallback changeCallback) { - return createTokenBasedSyntheticPassword(token, TOKEN_TYPE_STRONG, userId, - changeCallback); - } - - /** - * Create a weak token based Synthetic password for the given user. - * @return the handle of the weak token - */ - public long createWeakTokenBasedSyntheticPassword(byte[] token, int userId, - @Nullable EscrowTokenStateChangeCallback changeCallback) { - return createTokenBasedSyntheticPassword(token, TOKEN_TYPE_WEAK, userId, - changeCallback); - } - - /** * Create a token based Synthetic password of the given type for the given user. * @return the handle of the token */ @@ -1499,8 +1482,8 @@ public class SyntheticPasswordManager { private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) { final byte[] password = credential.isNone() ? DEFAULT_PASSWORD : credential.getCredential(); - return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP, - PASSWORD_TOKEN_LENGTH); + return scrypt(password, data.salt, 1 << data.scryptLogN, 1 << data.scryptLogR, + 1 << data.scryptLogP, PASSWORD_TOKEN_LENGTH); } private byte[] passwordTokenToGkInput(byte[] token) { @@ -1541,18 +1524,9 @@ public class SyntheticPasswordManager { return result; } - protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(); - private static byte[] bytesToHex(byte[] bytes) { - if (bytes == null) { - return "null".getBytes(); - } - byte[] hexBytes = new byte[bytes.length * 2]; - for ( int j = 0; j < bytes.length; j++ ) { - int v = bytes[j] & 0xFF; - hexBytes[j * 2] = HEX_ARRAY[v >>> 4]; - hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return hexBytes; + @VisibleForTesting + static byte[] bytesToHex(byte[] bytes) { + return HexEncoding.encodeToString(bytes).getBytes(); } /** diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index bdde4f6ad86b..b05e44f9e625 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -62,7 +62,8 @@ final class OverlayManagerShellCommand extends ShellCommand { private final Context mContext; private final IOverlayManager mInterface; private static final Map<String, Integer> TYPE_MAP = Map.of( - "color", TypedValue.TYPE_FIRST_COLOR_INT); + "color", TypedValue.TYPE_FIRST_COLOR_INT, + "string", TypedValue.TYPE_STRING); OverlayManagerShellCommand(@NonNull final Context ctx, @NonNull final IOverlayManager iom) { mContext = ctx; @@ -390,13 +391,17 @@ final class OverlayManagerShellCommand extends ShellCommand { type = Integer.parseUnsignedInt(typeString); } } - final int intData; - if (valueString.startsWith("0x")) { - intData = Integer.parseUnsignedInt(valueString.substring(2), 16); + if (type == TypedValue.TYPE_STRING) { + overlayBuilder.setResourceValue(resourceName, type, valueString); } else { - intData = Integer.parseUnsignedInt(valueString); + final int intData; + if (valueString.startsWith("0x")) { + intData = Integer.parseUnsignedInt(valueString.substring(2), 16); + } else { + intData = Integer.parseUnsignedInt(valueString); + } + overlayBuilder.setResourceValue(resourceName, type, intData); } - overlayBuilder.setResourceValue(resourceName, type, intData); } private int runEnableExclusive() throws RemoteException { diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java index 2db1c2029d9c..24ed6216f7fe 100644 --- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java +++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java @@ -294,6 +294,10 @@ final class ResolveIntentHelper { // non-launchable IntentSender which contains the failed intent is created. The // SendIntentException is thrown if the IntentSender#sendIntent is invoked. if (ris != null && !ris.isEmpty()) { + // am#isIntentSenderTargetedToPackage returns false if both package name and component + // name are set in the intent. Clear the package name to have the api return true and + // prevent the package existence info from side channel leaks by the api. + intent.setPackage(null); intent.setClassName(ris.get(0).activityInfo.packageName, ris.get(0).activityInfo.name); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b70f7a0fd213..406b9ee1e92a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3215,12 +3215,29 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } - if (mRootWindowContainer.getTopResumedActivity() == this - && getDisplayContent().mFocusedApp == this) { - ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: already on top, " - + "activity=%s", this); - return !isState(RESUMED); + // If this activity already positions on the top focused task, moving the task to front + // is not needed. But we still need to ensure this activity is focused because the + // current focused activity could be another activity in the same Task if activities are + // displayed on adjacent TaskFragments. + final ActivityRecord currentFocusedApp = mDisplayContent.mFocusedApp; + if (currentFocusedApp != null && currentFocusedApp.task == task) { + final Task topFocusableTask = mDisplayContent.getTask( + (t) -> t.isLeafTask() && t.isFocusable(), true /* traverseTopToBottom */); + if (task == topFocusableTask) { + if (currentFocusedApp == this) { + ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: already on top " + + "and focused, activity=%s", this); + } else { + ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: set focused, " + + "activity=%s", this); + mDisplayContent.setFocusedApp(this); + mAtmService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, + true /* updateInputWindows */); + } + return !isState(RESUMED); + } } + ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: activity=%s", this); rootTask.moveToFront(reason, task); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index c14e54ef586a..9637aca4c690 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2576,6 +2576,7 @@ class ActivityStarter { mInTask = null; } mInTaskFragment = inTaskFragment; + sendNewTaskFragmentResultRequestIfNeeded(); mStartFlags = startFlags; // If the onlyIfNeeded flag is set, then we can do this if the activity being launched @@ -2618,6 +2619,18 @@ class ActivityStarter { } } + private void sendNewTaskFragmentResultRequestIfNeeded() { + if (mStartActivity.resultTo != null && mInTaskFragment != null + && mInTaskFragment != mStartActivity.resultTo.getTaskFragment()) { + Slog.w(TAG, + "Activity is launching as a new TaskFragment, so cancelling activity result."); + mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho, + mStartActivity.requestCode, RESULT_CANCELED, + null /* data */, null /* dataGrants */); + mStartActivity.resultTo = null; + } + } + private void computeLaunchingTaskFlags() { // If the caller is not coming from another activity, but has given us an explicit task into // which they would like us to launch the new activity, then let's see about doing that. diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 4bb023c1c218..52bf220a647a 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1114,7 +1114,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // If a task is launching from a created-by-organizer task, it should be launched into the // same created-by-organizer task as well. Unless, the candidate task is already positioned // in the another adjacent task. - if (sourceTask != null) { + if (sourceTask != null && (candidateTask == null + // A pinned task relaunching should be handled by its task organizer. Skip fallback + // launch target of a pinned task from source task. + || candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) { Task launchTarget = sourceTask.getCreatedByOrganizerTask(); if (launchTarget != null && launchTarget.getAdjacentTaskFragment() != null) { if (candidateTask != null) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9d5b9455da13..43ebec814a63 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -122,7 +122,6 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; -import static com.android.server.wm.WindowContainer.SYNC_STATE_NONE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; @@ -2245,7 +2244,7 @@ public class WindowManagerService extends IWindowManager.Stub return 0; } - if (win.cancelAndRedraw()) { + if (win.cancelAndRedraw() && win.mPrepareSyncSeqId <= win.mLastSeqIdSentToRelayout) { result |= RELAYOUT_RES_CANCEL_AND_REDRAW; } @@ -2551,11 +2550,6 @@ public class WindowManagerService extends IWindowManager.Stub win.mLastSeqIdSentToRelayout = win.mSyncSeqId; outSyncIdBundle.putInt("seqid", win.mSyncSeqId); - // Only mark mAlreadyRequestedSync if there's an explicit sync request, and not if - // we're syncing due to mDrawHandlers - if (win.mSyncState != SYNC_STATE_NONE) { - win.mAlreadyRequestedSync = true; - } } else { outSyncIdBundle.putInt("seqid", -1); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 6728e63d055f..46091d842c2a 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -115,6 +115,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; @@ -391,7 +392,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ int mSyncSeqId = 0; int mLastSeqIdSentToRelayout = 0; - boolean mAlreadyRequestedSync; + + /** The last syncId associated with a prepareSync or 0 when no sync is active. */ + int mPrepareSyncSeqId = 0; /** * {@code true} when the client was still drawing for sync when the sync-set was finished or @@ -4421,7 +4424,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - pw.println(prefix + "mAlreadyRequestedSync=" + mAlreadyRequestedSync); + pw.println(prefix + "mPrepareSyncSeqId=" + mPrepareSyncSeqId); } @Override @@ -5913,6 +5916,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mWinAnimator.getSurfaceControl(); } + /** Drops a buffer for this window's view-root from a transaction */ + private void dropBufferFrom(Transaction t) { + SurfaceControl viewSurface = getClientViewRootSurface(); + if (viewSurface == null) return; + t.setBuffer(viewSurface, (android.hardware.HardwareBuffer) null); + } + @Override boolean prepareSync() { if (!mDrawHandlers.isEmpty()) { @@ -5928,7 +5938,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // to draw even if the children draw first or don't need to sync, so we start // in WAITING state rather than READY. mSyncState = SYNC_STATE_WAITING_FOR_DRAW; + + if (mPrepareSyncSeqId > 0) { + // another prepareSync during existing sync (eg. reparented), so pre-emptively + // drop buffer (if exists). If the buffer hasn't been received yet, it will be + // dropped in finishDrawing. + ProtoLog.d(WM_DEBUG_SYNC_ENGINE, "Preparing to sync a window that was already in the" + + " sync, so try dropping buffer. win=%s", this); + dropBufferFrom(mSyncTransaction); + } + mSyncSeqId++; + mPrepareSyncSeqId = mSyncSeqId; requestRedrawForSync(); return true; } @@ -5949,7 +5970,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mRedrawForSyncReported) { mClientWasDrawingForSync = true; } - mAlreadyRequestedSync = false; + mPrepareSyncSeqId = 0; + if (cancel) { + // This is leaving sync so any buffers left in the sync have a chance of + // being applied out-of-order and can also block the buffer queue for this + // window. To prevent this, drop the buffer. + dropBufferFrom(mSyncTransaction); + } super.finishSync(outMergedTransaction, cancel); } @@ -5971,6 +5998,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP .notifyStartingWindowDrawn(mActivityRecord); } + final boolean syncActive = mPrepareSyncSeqId > 0; + final boolean syncStillPending = syncActive && mPrepareSyncSeqId > syncSeqId; + if (syncStillPending && postDrawTransaction != null) { + ProtoLog.d(WM_DEBUG_SYNC_ENGINE, "Got a buffer for request id=%d but latest request is" + + " id=%d. Since the buffer is out-of-date, drop it. win=%s", syncSeqId, + mPrepareSyncSeqId, this); + // sync is waiting for a newer seqId, so this buffer is obsolete and can be dropped + // to free up the buffer queue. + dropBufferFrom(postDrawTransaction); + } + final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction, syncSeqId); boolean skipLayout = false; @@ -5983,10 +6021,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Layout is not needed because the window will be hidden by the fade leash. postDrawTransaction = null; skipLayout = true; - } else if (onSyncFinishedDrawing() && postDrawTransaction != null) { - mSyncTransaction.merge(postDrawTransaction); - // Consume the transaction because the sync group will merge it. - postDrawTransaction = null; + } else if (syncActive) { + if (!syncStillPending) { + onSyncFinishedDrawing(); + } + if (postDrawTransaction != null) { + mSyncTransaction.merge(postDrawTransaction); + // Consume the transaction because the sync group will merge it. + postDrawTransaction = null; + } } final boolean layoutNeeded = @@ -6218,6 +6261,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } public boolean cancelAndRedraw() { - return mSyncState != SYNC_STATE_NONE && mAlreadyRequestedSync; + // Cancel any draw requests during a sync. + return mPrepareSyncSeqId > 0; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 06c0e366ad1a..cbd574348de0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1981,6 +1981,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { mOwners.load(); setDeviceOwnershipSystemPropertyLocked(); + if (mOwners.hasDeviceOwner()) { + setGlobalSettingDeviceOwnerType( + mOwners.getDeviceOwnerType(mOwners.getDeviceOwnerPackageName())); + } } } @@ -8804,6 +8808,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { deleteTransferOwnershipBundleLocked(userId); toggleBackupServiceActive(UserHandle.USER_SYSTEM, true); pushUserControlDisabledPackagesLocked(userId); + setGlobalSettingDeviceOwnerType(DEVICE_OWNER_TYPE_DEFAULT); } private void clearApplicationRestrictions(int userId) { @@ -18363,6 +18368,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Test only admins can only set the device owner type more than once"); mOwners.setDeviceOwnerType(packageName, deviceOwnerType, isAdminTestOnly); + setGlobalSettingDeviceOwnerType(deviceOwnerType); + } + + // TODO(b/237065504): Allow mainline modules to get the device owner type. This is a workaround + // to get the device owner type in PermissionController. See HibernationPolicy.kt. + private void setGlobalSettingDeviceOwnerType(int deviceOwnerType) { + mInjector.binderWithCleanCallingIdentity( + () -> mInjector.settingsGlobalPutInt("device_owner_type", deviceOwnerType)); } @Override diff --git a/services/net/Android.bp b/services/net/Android.bp index 886a397c87e6..804ccc514df5 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -28,30 +28,6 @@ java_library_static { ], } -// Version of services.net for usage by the wifi mainline module. -// Note: This is compiled against module_current. -// TODO(b/172457099): This should be moved to networkstack-client, -// with dependencies moved to frameworks/libs/net right. -java_library { - name: "services.net-module-wifi", - sdk_version: "module_current", - min_sdk_version: "30", - static_libs: [ - // All the classes in netd_aidl_interface must be jarjar so they do not conflict with the - // classes generated by netd_aidl_interfaces-platform-java above. - "netd_aidl_interface-V3-java", - "networkstack-client", - "net-utils-services-common", - ], - apex_available: [ - "com.android.wifi", - ], - visibility: [ - "//packages/modules/Wifi/service", - "//packages/modules/Wifi/service/tests/wifitests", - ], -} - filegroup { name: "services-tethering-shared-srcs", srcs: [ diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java index 08cea06fd314..31fe18410182 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java +++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java @@ -21,14 +21,19 @@ import static com.android.compatibility.common.util.ShellUtils.runShellCommand; import static com.google.common.truth.Truth.assertThat; import android.app.AppGlobals; +import android.app.PendingIntent; +import android.content.Context; +import android.content.IntentSender; import android.content.pm.IPackageManager; import android.content.pm.ProviderInfo; import android.os.Process; import android.os.UserHandle; +import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,6 +59,7 @@ public class AppEnumerationInternalTests { private static final String TARGET_HAS_APPOP_PERMISSION = "com.android.appenumeration.hasappoppermission"; private static final String TARGET_SHARED_USER = "com.android.appenumeration.shareduid"; + private static final String TARGET_NON_EXISTENT = "com.android.appenumeration.nonexistent.pkg"; private static final String SYNC_PROVIDER_AUTHORITY = TARGET_SYNC_PROVIDER; private static final String PERMISSION_REQUEST_INSTALL_PACKAGES = @@ -134,6 +140,26 @@ public class AppEnumerationInternalTests { assertThat(uid).isEqualTo(Process.INVALID_UID); } + @Test + public void getLaunchIntentSenderForPackage_intentSender_cannotDetectPackage() + throws Exception { + installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */); + + final Context context = InstrumentationRegistry.getInstrumentation().getContext(); + final IntentSender sender = context.getPackageManager() + .getLaunchIntentSenderForPackage(TARGET_SHARED_USER); + assertThat(new PendingIntent(sender.getTarget()).isTargetedToPackage()).isTrue(); + sender.sendIntent(context, 0 /* code */, null /* intent */, + null /* onFinished */, null /* handler */); + + final IntentSender failedSender = InstrumentationRegistry.getInstrumentation().getContext() + .getPackageManager().getLaunchIntentSenderForPackage(TARGET_NON_EXISTENT); + assertThat(new PendingIntent(failedSender.getTarget()).isTargetedToPackage()).isTrue(); + Assert.assertThrows(IntentSender.SendIntentException.class, + () -> failedSender.sendIntent(context, 0 /* code */, null /* intent */, + null /* onFinished */, null /* handler */)); + } + private static void installPackage(String apkPath, boolean forceQueryable) { final StringBuilder cmd = new StringBuilder("pm install "); if (forceQueryable) { diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml index b424298e0ae0..65d0f218461a 100644 --- a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml +++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/AndroidManifest-sharedUser.xml @@ -19,6 +19,13 @@ package="com.android.appenumeration.shareduid" android:sharedUserId="com.android.appenumeration.shareduid"> <application> + <activity android:name="com.android.appenumeration.testapp.DummyActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.INFO"/> + </intent-filter> + </activity> <uses-library android:name="android.test.runner" /> </application> </manifest>
\ No newline at end of file diff --git a/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyActivity.java b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyActivity.java new file mode 100644 index 000000000000..bc5d3b5d022d --- /dev/null +++ b/services/tests/PackageManagerServiceTests/appenumeration/test-apps/target/src/com/android/appenumeration/testapp/DummyActivity.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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.appenumeration.testapp; + +import android.app.Activity; + +public class DummyActivity extends Activity { +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 388170bd24cb..a7ca08385b9f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -7848,7 +7848,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setDeviceOwner(); dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED); when(getServices().ipackageManager.getBlockUninstallForUser( - eq(packageName), eq(UserHandle.USER_SYSTEM))) + eq(packageName), eq(UserHandle.getCallingUserId()))) .thenReturn(true); assertThat(dpm.isUninstallBlocked(admin1, packageName)).isTrue(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index eae9ee7fc55a..09aa345bef22 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -468,18 +468,18 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { @Test public void testPasswordData_serializeDeserialize() { PasswordData data = new PasswordData(); - data.scryptN = 11; - data.scryptR = 22; - data.scryptP = 33; + data.scryptLogN = 11; + data.scryptLogR = 22; + data.scryptLogP = 33; data.credentialType = CREDENTIAL_TYPE_PASSWORD; data.salt = PAYLOAD; data.passwordHandle = PAYLOAD2; PasswordData deserialized = PasswordData.fromBytes(data.toBytes()); - assertEquals(11, deserialized.scryptN); - assertEquals(22, deserialized.scryptR); - assertEquals(33, deserialized.scryptP); + assertEquals(11, deserialized.scryptLogN); + assertEquals(22, deserialized.scryptLogR); + assertEquals(33, deserialized.scryptLogP); assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.credentialType); assertArrayEquals(PAYLOAD, deserialized.salt); assertArrayEquals(PAYLOAD2, deserialized.passwordHandle); @@ -491,9 +491,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { // wire format. byte[] serialized = new byte[] { 0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD_OR_PIN */ - 11, /* scryptN */ - 22, /* scryptR */ - 33, /* scryptP */ + 11, /* scryptLogN */ + 22, /* scryptLogR */ + 33, /* scryptLogP */ 0, 0, 0, 5, /* salt.length */ 1, 2, -1, -2, 55, /* salt */ 0, 0, 0, 6, /* passwordHandle.length */ @@ -501,9 +501,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { }; PasswordData deserialized = PasswordData.fromBytes(serialized); - assertEquals(11, deserialized.scryptN); - assertEquals(22, deserialized.scryptR); - assertEquals(33, deserialized.scryptP); + assertEquals(11, deserialized.scryptLogN); + assertEquals(22, deserialized.scryptLogR); + assertEquals(33, deserialized.scryptLogP); assertEquals(CREDENTIAL_TYPE_PASSWORD_OR_PIN, deserialized.credentialType); assertArrayEquals(PAYLOAD, deserialized.salt); assertArrayEquals(PAYLOAD2, deserialized.passwordHandle); @@ -574,6 +574,13 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } } + @Test + public void testHexEncodingIsUppercase() { + final byte[] raw = new byte[] { (byte)0xAB, (byte)0xCD, (byte)0xEF }; + final byte[] expected = new byte[] { 'A', 'B', 'C', 'D', 'E', 'F' }; + assertArrayEquals(expected, SyntheticPasswordManager.bytesToHex(raw)); + } + // b/62213311 //TODO: add non-migration work profile case, and unify/un-unify transition. //TODO: test token after user resets password diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 2a9fcb9d070b..7f09606d1c3a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -762,12 +762,20 @@ public class TaskDisplayAreaTests extends WindowTestsBase { Task actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */, adjacentRootTask /* sourceTask */, 0 /* launchFlags */, candidateTask); - assertSame(rootTask, actualRootTask.getRootTask()); + assertSame(rootTask, actualRootTask); // Verify the launch root task without candidate task actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, null /* options */, adjacentRootTask /* sourceTask */, 0 /* launchFlags */); - assertSame(adjacentRootTask, actualRootTask.getRootTask()); + assertSame(adjacentRootTask, actualRootTask); + + final Task pinnedTask = createTask( + mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); + // Verify not adjusting launch target for pinned candidate task + actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED, + ACTIVITY_TYPE_STANDARD, null /* options */, adjacentRootTask /* sourceTask */, + 0 /* launchFlags */, pinnedTask /* candidateTask */); + assertNull(actualRootTask); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 228cb65aab38..5f3096356bc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -475,5 +475,13 @@ public class TaskFragmentTest extends WindowTestsBase { assertFalse(activity0.isLetterboxedForFixedOrientationAndAspectRatio()); assertFalse(activity1.isLetterboxedForFixedOrientationAndAspectRatio()); assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation()); + + tf0.setResumedActivity(activity0, "test"); + tf1.setResumedActivity(activity1, "test"); + mDisplayContent.mFocusedApp = activity1; + + // Making the activity0 be the focused activity and ensure the focused app is updated. + activity0.moveFocusableActivityToTop("test"); + assertEquals(activity0, mDisplayContent.mFocusedApp); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index bb2e9639881a..1e0e8366c385 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -136,6 +136,7 @@ final class HotwordDetectionConnection { // The error codes are used for onError callback private static final int HOTWORD_DETECTION_SERVICE_DIED = -1; private static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2; + private static final int CALLBACK_DETECT_TIMEOUT = -3; // Hotword metrics private static final int METRICS_INIT_UNKNOWN_TIMEOUT = @@ -545,66 +546,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "triggerHardwareRecognitionEventForTestLocked"); } - detectFromDspSourceForTest(event, callback); - } - - private void detectFromDspSourceForTest(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, - IHotwordRecognitionStatusCallback externalCallback) { - Slog.v(TAG, "detectFromDspSourceForTest"); - IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() { - @Override - public void onDetected(HotwordDetectedResult result) throws RemoteException { - Slog.v(TAG, "onDetected"); - synchronized (mLock) { - if (!mValidatingDspTrigger) { - Slog.i(TAG, "Ignored hotword detected since trigger has been handled"); - return; - } - mValidatingDspTrigger = false; - try { - enforcePermissionsForDataDelivery(); - enforceExtraKeyphraseIdNotLeaked(result, recognitionEvent); - } catch (SecurityException e) { - externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION); - return; - } - externalCallback.onKeyphraseDetected(recognitionEvent, result); - if (result != null) { - Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) - + " bits from hotword trusted process"); - if (mDebugHotwordLogging) { - Slog.i(TAG, "Egressed detected result: " + result); - } - } - } - } - - @Override - public void onRejected(HotwordRejectedResult result) throws RemoteException { - Slog.v(TAG, "onRejected"); - synchronized (mLock) { - if (mValidatingDspTrigger) { - mValidatingDspTrigger = false; - externalCallback.onRejected(result); - if (mDebugHotwordLogging && result != null) { - Slog.i(TAG, "Egressed rejected result: " + result); - } - } else { - Slog.i(TAG, "Ignored hotword rejected since trigger has been handled"); - } - } - } - }; - - synchronized (mLock) { - mValidatingDspTrigger = true; - mRemoteHotwordDetectionService.run( - service -> service.detectFromDspSource( - recognitionEvent, - recognitionEvent.getCaptureFormat(), - VALIDATION_TIMEOUT_MILLIS, - internalCallback)); - } + detectFromDspSource(event, callback); } private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, @@ -613,6 +555,7 @@ final class HotwordDetectionConnection { Slog.d(TAG, "detectFromDspSource"); } + AtomicBoolean timeoutDetected = new AtomicBoolean(false); // TODO: consider making this a non-anonymous class. IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() { @Override @@ -621,12 +564,12 @@ final class HotwordDetectionConnection { Slog.d(TAG, "onDetected"); } synchronized (mLock) { - // TODO: If the dsp trigger comes in after the timeout, we will log both events. - // Because we don't enforce the timeout yet. We should add some synchronizations - // within the runnable to prevent the race condition to log both events. if (mCancellationKeyPhraseDetectionFuture != null) { mCancellationKeyPhraseDetectionFuture.cancel(true); } + if (timeoutDetected.get()) { + return; + } HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED); @@ -668,6 +611,9 @@ final class HotwordDetectionConnection { if (mCancellationKeyPhraseDetectionFuture != null) { mCancellationKeyPhraseDetectionFuture.cancel(true); } + if (timeoutDetected.get()) { + return; + } HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED); @@ -689,21 +635,29 @@ final class HotwordDetectionConnection { synchronized (mLock) { mValidatingDspTrigger = true; - mRemoteHotwordDetectionService.run( - service -> { - // TODO: avoid allocate every time - mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule( - () -> HotwordMetricsLogger - .writeKeyphraseTriggerEvent(mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT), - VALIDATION_TIMEOUT_MILLIS, - TimeUnit.MILLISECONDS); - service.detectFromDspSource( - recognitionEvent, - recognitionEvent.getCaptureFormat(), - VALIDATION_TIMEOUT_MILLIS, - internalCallback); - }); + mRemoteHotwordDetectionService.run(service -> { + mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule( + () -> { + // TODO: avoid allocate every time + timeoutDetected.set(true); + Slog.w(TAG, "Timed out on #detectFromDspSource"); + HotwordMetricsLogger.writeKeyphraseTriggerEvent( + mDetectorType, + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT); + try { + externalCallback.onError(CALLBACK_DETECT_TIMEOUT); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to report onError status: ", e); + } + }, + VALIDATION_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS); + service.detectFromDspSource( + recognitionEvent, + recognitionEvent.getCaptureFormat(), + VALIDATION_TIMEOUT_MILLIS, + internalCallback); + }); } } diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp index 62e16a5b83de..f026bea80470 100644 --- a/tests/ApkVerityTest/Android.bp +++ b/tests/ApkVerityTest/Android.bp @@ -37,8 +37,8 @@ java_test_host { "general-tests", "vts", ], - target_required: [ - "block_device_writer_module", + data_device_bins_both: [ + "block_device_writer", ], data: [ ":ApkVerityTestCertDer", diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml index 3c8e1ed99604..2a0a2c76e50f 100644 --- a/tests/ApkVerityTest/AndroidTest.xml +++ b/tests/ApkVerityTest/AndroidTest.xml @@ -31,10 +31,18 @@ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> <option name="cleanup" value="true" /> - <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" /> <option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" /> </target_preparer> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <!-- The build system produces both 32 and 64 bit variants with bitness suffix. Let + FilePusher find the filename with bitness and push to a remote name without bitness. + --> + <option name="append-bitness" value="true" /> + <option name="cleanup" value="true" /> + <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" /> + </target_preparer> + <!-- Skip on HWASan. TODO(b/232288278): Re-enable --> <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" /> <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp index fdfa41fd4ca9..0002447d17f2 100644 --- a/tests/ApkVerityTest/block_device_writer/Android.bp +++ b/tests/ApkVerityTest/block_device_writer/Android.bp @@ -24,12 +24,7 @@ package { } cc_test { - // Depending on how the test runs, the executable may be uploaded to different location. - // Before the bug in the file pusher is fixed, workaround by making the name unique. - // See b/124718249#comment12. - name: "block_device_writer_module", - stem: "block_device_writer", - + name: "block_device_writer", srcs: ["block_device_writer.cpp"], cflags: [ "-D_FILE_OFFSET_BITS=64", @@ -42,20 +37,13 @@ cc_test { "libbase", "libutils", ], - // For some reasons, cuttlefish (x86) uses x86_64 test suites for testing. Unfortunately, when - // the uploader does not pick up the executable from correct output location. The following - // workaround allows the test to: - // * upload the 32-bit exectuable for both 32 and 64 bits devices to use - // * refer to the same executable name in Java - // * no need to force the Java test to be archiecture specific. - // - // See b/145573317 for details. + compile_multilib: "both", multilib: { lib32: { - suffix: "", + suffix: "32", }, lib64: { - suffix: "64", // not really used + suffix: "64", }, }, diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java index 5c2c15b22bb0..9be02ec3be86 100644 --- a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java +++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java @@ -32,11 +32,12 @@ import java.util.ArrayList; * <p>To use this class, please push block_device_writer binary to /data/local/tmp. * 1. In Android.bp, add: * <pre> - * target_required: ["block_device_writer_module"], + * data_device_bins_both: ["block_device_writer"], * </pre> * 2. In AndroidText.xml, add: * <pre> - * <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + * <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + * <option name="append-bitness" value="true" /> * <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" /> * </target_preparer> * </pre> diff --git a/tests/RollbackTest/SampleRollbackApp/Android.bp b/tests/RollbackTest/SampleRollbackApp/Android.bp new file mode 100644 index 000000000000..a18488d8f57f --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2022 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_app { + name: "SampleRollbackApp", + srcs: [ + "src/**/*.java", + ], + resource_dirs: ["res"], + certificate: "platform", + sdk_version: "system_current", +} diff --git a/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml b/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml new file mode 100644 index 000000000000..5a135c978343 --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sample.rollbackapp" > + <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" /> + <application + android:label="@string/title_activity_main"> + <activity + android:name="com.android.sample.rollbackapp.MainActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/RollbackTest/SampleRollbackApp/res/layout/activity_main.xml b/tests/RollbackTest/SampleRollbackApp/res/layout/activity_main.xml new file mode 100644 index 000000000000..3fb987bb539c --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/res/layout/activity_main.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <Button + android:id="@+id/trigger_rollback_button" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + style="?android:attr/buttonBarButtonStyle" + android:text="Rollback Selected" /> + + <ListView + android:id="@+id/listView" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:divider="?android:attr/dividerHorizontal" + android:dividerHeight="1dp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/RollbackTest/SampleRollbackApp/res/layout/listitem_rollbackinfo.xml b/tests/RollbackTest/SampleRollbackApp/res/layout/listitem_rollbackinfo.xml new file mode 100644 index 000000000000..f650dd5d2230 --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/res/layout/listitem_rollbackinfo.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" +> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingTop="10dp" + android:paddingLeft="10dp" + android:paddingRight="10dp"> + <TextView android:id="@+id/rollback_id" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="20dp"/> + <TextView android:id="@+id/rollback_packages" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="16dp"/> + <CheckBox android:id="@+id/checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Roll Back"/> + </LinearLayout> +</RelativeLayout>
\ No newline at end of file diff --git a/tests/RollbackTest/SampleRollbackApp/res/values/strings.xml b/tests/RollbackTest/SampleRollbackApp/res/values/strings.xml new file mode 100644 index 000000000000..a85b6800a146 --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> + +<resources> + <string name="title_activity_main" description="Launcher title">Rollback Sample App</string> +</resources>
\ No newline at end of file diff --git a/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java b/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java new file mode 100644 index 000000000000..916551a8ce6d --- /dev/null +++ b/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 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.sample.rollbackapp; + +import static android.app.PendingIntent.FLAG_MUTABLE; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.rollback.PackageRollbackInfo; +import android.content.rollback.RollbackInfo; +import android.content.rollback.RollbackManager; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MainActivity extends Activity { + + List<Integer> mIdsToRollback = new ArrayList<>(); + Button mTriggerRollbackButton; + RollbackManager mRollbackManager; + static final String ROLLBACK_ID_EXTRA = "rollbackId"; + static final String ACTION_NAME = MainActivity.class.getName(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ListView rollbackListView = findViewById(R.id.listView); + mRollbackManager = getApplicationContext().getSystemService(RollbackManager.class); + initTriggerRollbackButton(); + + // Populate list of available rollbacks. + List<RollbackInfo> availableRollbacks = mRollbackManager.getAvailableRollbacks(); + CustomAdapter adapter = new CustomAdapter(availableRollbacks); + rollbackListView.setAdapter(adapter); + + // Register receiver for rollback status events. + getApplicationContext().registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, + Intent intent) { + int rollbackId = intent.getIntExtra(ROLLBACK_ID_EXTRA, -1); + int rollbackStatusCode = intent.getIntExtra(RollbackManager.EXTRA_STATUS, + RollbackManager.STATUS_FAILURE); + String rollbackStatus = "FAILED"; + if (rollbackStatusCode == RollbackManager.STATUS_SUCCESS) { + rollbackStatus = "SUCCESS"; + } + makeToast("Status for rollback ID " + rollbackId + " is " + rollbackStatus); + }}, new IntentFilter(ACTION_NAME), Context.RECEIVER_NOT_EXPORTED); + } + + private void initTriggerRollbackButton() { + mTriggerRollbackButton = findViewById(R.id.trigger_rollback_button); + mTriggerRollbackButton.setClickable(false); + mTriggerRollbackButton.setOnClickListener(v -> { + // Commits all selected rollbacks. Rollback status events will be sent to our receiver. + for (int i = 0; i < mIdsToRollback.size(); i++) { + Intent intent = new Intent(ACTION_NAME); + intent.putExtra(ROLLBACK_ID_EXTRA, mIdsToRollback.get(i)); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + getApplicationContext(), 0, intent, FLAG_MUTABLE); + mRollbackManager.commitRollback(mIdsToRollback.get(i), + Collections.emptyList(), + pendingIntent.getIntentSender()); + } + }); + } + + + + private void makeToast(String message) { + runOnUiThread(() -> Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show()); + } + + public class CustomAdapter extends BaseAdapter { + List<RollbackInfo> mRollbackInfos; + LayoutInflater mInflater = LayoutInflater.from(getApplicationContext()); + + CustomAdapter(List<RollbackInfo> rollbackInfos) { + mRollbackInfos = rollbackInfos; + } + + @Override + public int getCount() { + return mRollbackInfos.size(); + } + + @Override + public Object getItem(int position) { + return mRollbackInfos.get(position); + } + + @Override + public long getItemId(int position) { + return mRollbackInfos.get(position).getRollbackId(); + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + if (view == null) { + view = mInflater.inflate(R.layout.listitem_rollbackinfo, null); + } + RollbackInfo rollbackInfo = mRollbackInfos.get(position); + TextView rollbackIdView = view.findViewById(R.id.rollback_id); + rollbackIdView.setText("Rollback ID " + rollbackInfo.getRollbackId()); + TextView rollbackPackagesTextView = view.findViewById(R.id.rollback_packages); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < rollbackInfo.getPackages().size(); i++) { + PackageRollbackInfo pkgInfo = rollbackInfo.getPackages().get(i); + sb.append(pkgInfo.getPackageName() + ": " + + pkgInfo.getVersionRolledBackFrom().getLongVersionCode() + " -> " + + pkgInfo.getVersionRolledBackTo().getLongVersionCode() + ","); + } + sb.deleteCharAt(sb.length() - 1); + rollbackPackagesTextView.setText(sb.toString()); + CheckBox checkbox = view.findViewById(R.id.checkbox); + checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + mIdsToRollback.add(rollbackInfo.getRollbackId()); + } else { + mIdsToRollback.remove(Integer.valueOf(rollbackInfo.getRollbackId())); + } + mTriggerRollbackButton.setClickable(mIdsToRollback.size() > 0); + }); + return view; + } + } +} |