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

Commit 454c5a69 authored by Sumedh Sen's avatar Sumedh Sen Committed by Android (Google) Code Review
Browse files

Merge changes Ib92caadd,I10342c9f,I49a6499a,I81177783,I434a3b1d, ... into main

* changes:
  On negative user action, cancel the install
  Handle uninstall result - caller does not want the result back.
  Handle uninstall result - Caller wants result back
  Initiate uninstall on confirmation from the user
  Introduce a receiver for ACTION_UNINSTALL_COMMIT broadcast
  Show user prompt for uninstall
  Compute app data size in case of fragile user data
  Compute dialog message when target user is different from current user
  Generate data for user confirmation snippet
  Handle uninstall abort case and show appropriate dialog
  Introduce an interface to listen to user actions while uninstalling
  Add additional checks on received uninstall request
  Process the incoming uninstall intent to this app
parents 01b3a621 f79bba70
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -156,6 +156,15 @@
            </intent-filter>
        </receiver>

        <receiver android:name=".v2.model.UninstallEventReceiver"
            android:permission="android.permission.INSTALL_PACKAGES"
            android:exported="false"
            android:enabled="false">
            <intent-filter android:priority="1">
                <action android:name="com.android.packageinstaller.ACTION_UNINSTALL_COMMIT" />
            </intent-filter>
        </receiver>

        <receiver android:name=".PackageInstalledReceiver"
                android:exported="false">
            <intent-filter android:priority="1">
+20 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.File;
@@ -403,6 +405,24 @@ public class PackageUtil {
        }
    }

    /**
     * Is a profile part of a user?
     *
     * @param userManager The user manager
     * @param userHandle The handle of the user
     * @param profileHandle The handle of the profile
     *
     * @return If the profile is part of the user or the profile parent of the user
     */
    public static boolean isProfileOfOrSame(UserManager userManager, UserHandle userHandle,
        UserHandle profileHandle) {
        if (userHandle.equals(profileHandle)) {
            return true;
        }
        return userManager.getProfileParent(profileHandle) != null
            && userManager.getProfileParent(profileHandle).equals(userHandle);
    }

    /**
     * The class to hold an incoming package's icon and label.
     * See {@link #getAppSnippet(Context, SessionInfo)},
+85 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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
 *
 *      https://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.packageinstaller.v2.model;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;

/**
 * Receives uninstall events and persists them using a {@link EventResultPersister}.
 */
public class UninstallEventReceiver extends BroadcastReceiver {
    private static final Object sLock = new Object();
    private static EventResultPersister sReceiver;

    /**
     * Get the event receiver persisting the results
     *
     * @return The event receiver.
     */
    @NonNull private static EventResultPersister getReceiver(@NonNull Context context) {
        synchronized (sLock) {
            if (sReceiver == null) {
                sReceiver = new EventResultPersister(
                        TemporaryFileManager.getUninstallStateFile(context));
            }
        }

        return sReceiver;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        getReceiver(context).onEventReceived(context, intent);
    }

    /**
     * Add an observer. If there is already an event for this id, call back inside of this call.
     *
     * @param context  A context of the current app
     * @param id       The id the observer is for or {@code GENERATE_NEW_ID} to generate a new one.
     * @param observer The observer to call back.
     *
     * @return The id for this event
     */
    public static int addObserver(@NonNull Context context, int id,
            @NonNull EventResultPersister.EventResultObserver observer)
            throws EventResultPersister.OutOfIdsException {
        return getReceiver(context).addObserver(id, observer);
    }

    /**
     * Remove a observer.
     *
     * @param context  A context of the current app
     * @param id The id the observer was added for
     */
    static void removeObserver(@NonNull Context context, int id) {
        getReceiver(context).removeObserver(id);
    }

    /**
     * @param context A context of the current app
     *
     * @return A new uninstall id
     */
    static int getNewId(@NonNull Context context) throws EventResultPersister.OutOfIdsException {
        return getReceiver(context).getNewId();
    }
}
+685 −0

File changed.

Preview size limit exceeded, changes collapsed.

+71 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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
 *
 *      https://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.packageinstaller.v2.model.uninstallstagedata;

import android.app.Activity;
import com.android.packageinstaller.R;

public class UninstallAborted extends UninstallStage {

    public static final int ABORT_REASON_GENERIC_ERROR = 0;
    public static final int ABORT_REASON_APP_UNAVAILABLE = 1;
    public static final int ABORT_REASON_USER_NOT_ALLOWED = 2;
    private final int mStage = UninstallStage.STAGE_ABORTED;
    private final int mAbortReason;
    private final int mDialogTitleResource;
    private final int mDialogTextResource;
    private final int mActivityResultCode = Activity.RESULT_FIRST_USER;

    public UninstallAborted(int abortReason) {
        mAbortReason = abortReason;
        switch (abortReason) {
            case ABORT_REASON_APP_UNAVAILABLE -> {
                mDialogTitleResource = R.string.app_not_found_dlg_title;
                mDialogTextResource = R.string.app_not_found_dlg_text;
            }
            case ABORT_REASON_USER_NOT_ALLOWED -> {
                mDialogTitleResource = 0;
                mDialogTextResource = R.string.user_is_not_allowed_dlg_text;
            }
            default -> {
                mDialogTitleResource = 0;
                mDialogTextResource = R.string.generic_error_dlg_text;
            }
        }
    }

    public int getAbortReason() {
        return mAbortReason;
    }

    public int getActivityResultCode() {
        return mActivityResultCode;
    }

    public int getDialogTitleResource() {
        return mDialogTitleResource;
    }

    public int getDialogTextResource() {
        return mDialogTextResource;
    }

    @Override
    public int getStageCode() {
        return mStage;
    }
}
Loading