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

Commit 97b1bba4 authored by Holly Sun's avatar Holly Sun
Browse files

Implement Install Apps button in Private Space.

UX mock: https://www.figma.com/file/K6bIIcG882EiJNjxvSWsFT/V%E2%80%A2-Private-Space?node-id=7246%3A83750&mode=dev
UX icon spec: https://www.figma.com/file/K6bIIcG882EiJNjxvSWsFT/V%E2%80%A2-Private-Space?type=design&node-id=19979-224329&mode=design&t=50SDFdomAtonNU4V-0

Video: https://drive.google.com/file/d/1VtTzxR46dLiaozOo6sOHADv1qTcBOwDP/view?usp=sharing
Screenshot:
https://screenshot.googleplex.com/3ShcUozVrkGMHbc
https://screenshot.googleplex.com/3F4c3yzJ7RUpma7

Reason to use PrivateSpaceInstallAppButtonInfo: reuse `VIEW_TYPE_ICON`, which needs an AppInfo.

Bug: 308064949
Test: manual
Flag: ACONFIG com.android.launcher3.private_space_app_installer_button development
Change-Id: I3fb27fae8324d4b276816b17f9b0a2d9b6f33ed2
parent a3daee40
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2024 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="60dp"
    android:height="60dp"
    android:viewportWidth="60"
    android:viewportHeight="60">
    <group>
        <clip-path
            android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z" />
        <path
            android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z"
            android:fillColor="@color/material_color_surface_bright" />
        <path
            android:pathData="M29 31h-6v-2h6v-6h2v6h6v2h-6v6h-2v-6Z"
            android:fillColor="@color/material_color_on_surface_variant" />
    </group>
</vector>
+4 −0
Original line number Diff line number Diff line
@@ -461,6 +461,10 @@
    <string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
    <!-- Description for Private Space Transition button -->
    <string name="ps_container_transition">Private Space Transitioning</string>
    <!-- Title for Private Space install app icon -->
    <string name="ps_add_button_label">Install apps</string>
    <!-- Content description for install app icon -->
    <string name="ps_add_button_content_description">Install apps to Private Space</string>

    <!-- Strings for bubble bar -->
    <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
+2 −0
Original line number Diff line number Diff line
@@ -322,6 +322,8 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
                    break;
                case PrivateProfileManager.STATE_ENABLED:
                    // Add PS Apps only in Enabled State.
                    mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems);
                    position++;
                    addAppsWithSections(mPrivateApps, position);
                    if (mActivityContext.getAppsView() != null) {
                        mActivityContext.getAppsView().getActiveRecyclerView()
+44 −0
Original line number Diff line number Diff line
@@ -17,11 +17,14 @@
package com.android.launcher3.allapps;

import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -30,13 +33,21 @@ import android.os.UserManager;

import androidx.annotation.VisibleForTesting;

import com.android.launcher3.BuildConfig;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.UserIconInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
@@ -71,6 +82,39 @@ public class PrivateProfileManager extends UserProfileManager {
        return adapterItems.size();
    }

    /** Adds Private Space install app button to the layout. */
    public void addPrivateSpaceInstallAppButton(List<BaseAllAppsAdapter.AdapterItem> adapterItems) {
        Context context = mAllApps.getContext();
        // Prepare intent
        UserCache userCache = UserCache.getInstance(context);
        UserHandle userHandle = userCache.getUserProfiles().stream()
                .filter(user -> userCache.getUserInfo(user).type == UserIconInfo.TYPE_PRIVATE)
                .findFirst()
                .orElse(null);
        Intent intent = ApiWrapper.getAppMarketActivityIntent(context,
                BuildConfig.APPLICATION_ID, userHandle);

        // Prepare bitmapInfo
        Intent.ShortcutIconResource shortcut = Intent.ShortcutIconResource.fromContext(
                context, com.android.launcher3.R.drawable.private_space_install_app_icon);
        BitmapInfo bitmapInfo = LauncherIcons.obtain(context).createIconBitmap(shortcut);

        AppInfo itemInfo = new AppInfo();
        itemInfo.title = context.getResources().getString(R.string.ps_add_button_label);
        itemInfo.intent = intent;
        itemInfo.bitmap = bitmapInfo;
        itemInfo.contentDescription = context.getResources().getString(
                com.android.launcher3.R.string.ps_add_button_content_description);

        BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
        item.itemInfo = itemInfo;
        item.decorationInfo = new SectionDecorationInfo(context, ROUND_NOTHING,
                /* decorateTogether */ true);

        adapterItems.add(item);
        mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
    }

    /** Disables quiet mode for Private Space User Profile. */
    public void unlockPrivateProfile() {
        enableQuietMode(false);
+2 −1
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
     */
    public Intent intent;

    @NonNull
    // componentName for the Private Space Install App button can be null
    @Nullable
    public ComponentName componentName;

    // Section name used for indexing.