Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 597cb089 authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Automerger Merge Worker
Browse files

Merge changes from topic "oms-transactional-api" am: b9ba6a8d am: f50bf40b am: 13405917

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1236071

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I1c9be5b9bd85ea9a54b06b1b39a8d89e8d96206c
parents ec9006cc 13405917
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content.om;

import android.content.om.OverlayInfo;
import android.content.om.OverlayManagerTransaction;

/**
 * Api for getting information about overlay packages.
@@ -163,4 +164,18 @@ interface IOverlayManager {
     * @param packageName The name of the overlay package whose idmap should be deleted.
     */
    void invalidateCachesForOverlay(in String packageName, in int userIs);

    /**
     * Perform a series of requests related to overlay packages. This is an
     * atomic operation: either all requests were performed successfully and
     * the changes were propagated to the rest of the system, or at least one
     * request could not be performed successfully and nothing is changed and
     * nothing is propagated to the rest of the system.
     *
     * @see OverlayManagerTransaction
     *
     * @param transaction the series of overlay related requests to perform
     * @throws SecurityException if the transaction failed
     */
    void commit(in OverlayManagerTransaction transaction);
}
+23 −0
Original line number Diff line number Diff line
@@ -253,6 +253,29 @@ public class OverlayManager {
        }
    }

    /**
     * Perform a series of requests related to overlay packages. This is an
     * atomic operation: either all requests were performed successfully and
     * the changes were propagated to the rest of the system, or at least one
     * request could not be performed successfully and nothing is changed and
     * nothing is propagated to the rest of the system.
     *
     * @see OverlayManagerTransaction
     *
     * @param transaction the series of overlay related requests to perform
     * @throws Exception if not all the requests could be successfully and
     *         atomically executed
     *
     * @hide
     */
    public void commit(@NonNull final OverlayManagerTransaction transaction) {
        try {
            mService.commit(transaction);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Starting on R, actor enforcement and app visibility changes introduce additional failure
     * cases, but the SecurityException thrown with these checks is unexpected for existing
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.content.om;

parcelable OverlayManagerTransaction;
+216 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.content.om;

import static com.android.internal.util.Preconditions.checkNotNull;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Container for a batch of requests to the OverlayManagerService.
 *
 * Transactions are created using a builder interface. Example usage:
 *
 * final OverlayManager om = ctx.getSystemService(OverlayManager.class);
 * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
 *     .setEnabled(...)
 *     .setEnabled(...)
 *     .build();
 * om.commit(t);
 *
 * @hide
 */
public class OverlayManagerTransaction
        implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
    // TODO: remove @hide from this class when OverlayManager is added to the
    // SDK, but keep OverlayManagerTransaction.Request @hidden
    private final List<Request> mRequests;

    OverlayManagerTransaction(@NonNull final List<Request> requests) {
        checkNotNull(requests);
        if (requests.contains(null)) {
            throw new IllegalArgumentException("null request");
        }
        mRequests = requests;
    }

    private OverlayManagerTransaction(@NonNull final Parcel source) {
        final int size = source.readInt();
        mRequests = new ArrayList<Request>(size);
        for (int i = 0; i < size; i++) {
            final int request = source.readInt();
            final String packageName = source.readString();
            final int userId = source.readInt();
            mRequests.add(new Request(request, packageName, userId));
        }
    }

    @Override
    public Iterator<Request> iterator() {
        return mRequests.iterator();
    }

    @Override
    public String toString() {
        return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
    }

    /**
     * A single unit of the transaction, such as a request to enable an
     * overlay, or to disable an overlay.
     *
     * @hide
     */
    public static class Request {
        @IntDef(prefix = "TYPE_", value = {
                TYPE_SET_ENABLED,
                TYPE_SET_DISABLED,
        })
        @Retention(RetentionPolicy.SOURCE)
        @interface RequestType {}

        public static final int TYPE_SET_ENABLED = 0;
        public static final int TYPE_SET_DISABLED = 1;

        @RequestType public final int type;
        public final String packageName;
        public final int userId;

        public Request(@RequestType final int type, @NonNull final String packageName,
                final int userId) {
            this.type = type;
            this.packageName = packageName;
            this.userId = userId;
        }

        @Override
        public String toString() {
            return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
                    type, typeToString(), packageName, userId);
        }

        /**
         * Translate the request type into a human readable string. Only
         * intended for debugging.
         *
         * @hide
         */
        public String typeToString() {
            switch (type) {
                case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
                case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
                default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
            }
        }
    }

    /**
     * Builder class for OverlayManagerTransaction objects.
     *
     * @hide
     */
    public static class Builder {
        private final List<Request> mRequests = new ArrayList<>();

        /**
         * Request that an overlay package be enabled and change its loading
         * order to the last package to be loaded, or disabled
         *
         * If the caller has the correct permissions, it is always possible to
         * disable an overlay. Due to technical and security reasons it may not
         * always be possible to enable an overlay, for instance if the overlay
         * does not successfully overlay any target resources due to
         * overlayable policy restrictions.
         *
         * An enabled overlay is a part of target package's resources, i.e. it will
         * be part of any lookups performed via {@link android.content.res.Resources}
         * and {@link android.content.res.AssetManager}. A disabled overlay will no
         * longer affect the resources of the target package. If the target is
         * currently running, its outdated resources will be replaced by new ones.
         *
         * @param packageName The name of the overlay package.
         * @param enable true to enable the overlay, false to disable it.
         * @return this Builder object, so you can chain additional requests
         */
        public Builder setEnabled(@NonNull String packageName, boolean enable) {
            return setEnabled(packageName, enable, UserHandle.myUserId());
        }

        /**
         * @hide
         */
        public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
            checkNotNull(packageName);
            @Request.RequestType final int type =
                enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
            mRequests.add(new Request(type, packageName, userId));
            return this;
        }

        /**
         * Create a new transaction out of the requests added so far. Execute
         * the transaction by calling OverlayManager#commit.
         *
         * @see OverlayManager#commit
         * @return a new transaction
         */
        public OverlayManagerTransaction build() {
            return new OverlayManagerTransaction(mRequests);
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        final int size = mRequests.size();
        dest.writeInt(size);
        for (int i = 0; i < size; i++) {
            final Request req = mRequests.get(i);
            dest.writeInt(req.type);
            dest.writeString(req.packageName);
            dest.writeInt(req.userId);
        }
    }

    public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
            new Parcelable.Creator<OverlayManagerTransaction>() {

        @Override
        public OverlayManagerTransaction createFromParcel(Parcel source) {
            return new OverlayManagerTransaction(source);
        }

        @Override
        public OverlayManagerTransaction[] newArray(int size) {
            return new OverlayManagerTransaction[size];
        }
    };
}
+5 −1
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@ android_test {
    name: "OverlayDeviceTests",
    srcs: ["src/**/*.java"],
    platform_apis: true,
    static_libs: ["androidx.test.rules"],
    certificate: "platform",
    static_libs: [
        "androidx.test.rules",
        "testng",
    ],
    test_suites: ["device-tests"],
    data: [
        ":OverlayDeviceTests_AppOverlayOne",
Loading