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

Commit d0a91038 authored by Yanting Yang's avatar Yanting Yang
Browse files

Update the card behavior of Low Storage slice

If used storage >= 85%, show low storage slice to all clients. Else, a
generic storage slice with error flag will be given. Home page will
check error flag in loading eligible cards.

Bug: 114808204
Test: robotests, visual
Change-Id: I757c46b3bbff785dc112fec6bdc37e5ce9269ed8
parent 72b25d65
Loading
Loading
Loading
Loading
+44 −38
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.net.Uri;
import android.os.storage.StorageManager;
import android.text.format.Formatter;
import android.util.Log;

import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -45,10 +44,8 @@ import java.text.NumberFormat;

public class LowStorageSlice implements CustomSliceable {

    private static final String TAG = "LowStorageSlice";

    /**
     * If user used >= 85% storage.
     * If used storage >= 85%, it would be low storage.
     */
    private static final double LOW_STORAGE_THRESHOLD = 0.85;

@@ -60,45 +57,37 @@ public class LowStorageSlice implements CustomSliceable {

    @Override
    public Slice getSlice() {
        // Get current storage percentage from StorageManager.
        // Get used storage percentage from StorageManager.
        final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
                new StorageManagerVolumeProvider(mContext.getSystemService(StorageManager.class)));
        final double currentStoragePercentage =
                (double) (info.totalBytes - info.freeBytes) / info.totalBytes;
        final double usedPercentage = (double) (info.totalBytes - info.freeBytes) / info.totalBytes;

        // Generate Low storage Slice.
        final String percentageString = NumberFormat.getPercentInstance().format(usedPercentage);
        final String freeSizeString = Formatter.formatFileSize(mContext, info.freeBytes);
        final ListBuilder listBuilder = new ListBuilder(mContext,
                CustomSliceRegistry.LOW_STORAGE_SLICE_URI, ListBuilder.INFINITY).setAccentColor(
                Utils.getColorAccentDefaultColor(mContext));
        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_storage);

        // Used storage < 85%. NOT show Low storage Slice.
        if (currentStoragePercentage < LOW_STORAGE_THRESHOLD) {
            /**
             * TODO(b/114808204): Contextual Home Page - "Low Storage"
             * The behavior is under decision making, will update new behavior or remove TODO later.
             */
            Log.i(TAG, "Not show low storage slice, not match condition.");
            return null;
        if (usedPercentage < LOW_STORAGE_THRESHOLD) {
            // For clients that ignore error checking, a generic storage slice will be given.
            final CharSequence titleStorage = mContext.getText(R.string.storage_settings);
            final String summaryStorage = mContext.getString(R.string.storage_summary,
                    percentageString, freeSizeString);

            return listBuilder
                    .addRow(buildRowBuilder(titleStorage, summaryStorage, icon))
                    .setIsError(true)
                    .build();
        }

        // Show Low storage Slice.
        final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_storage);
        final CharSequence title = mContext.getText(R.string.storage_menu_free);
        final SliceAction primarySliceAction = SliceAction.createDeeplink(
                PendingIntent.getActivity(mContext, 0, getIntent(), 0), icon,
                ListBuilder.ICON_IMAGE, title);
        final String lowStorageSummary = mContext.getString(R.string.low_storage_summary,
                NumberFormat.getPercentInstance().format(currentStoragePercentage),
                Formatter.formatFileSize(mContext, info.freeBytes));
        final CharSequence titleLowStorage = mContext.getText(R.string.storage_menu_free);
        final String summaryLowStorage = mContext.getString(R.string.low_storage_summary,
                percentageString, freeSizeString);

        /**
         * TODO(b/114808204): Contextual Home Page - "Low Storage"
         * Slices doesn't support "Icon on the left" in header. Now we intend to start with Icon
         * right aligned. Will update the icon to left until Slices support it.
         */
        return new ListBuilder(mContext, CustomSliceRegistry.LOW_STORAGE_SLICE_URI,
                ListBuilder.INFINITY)
                .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                .addRow(new RowBuilder()
                        .setTitle(title)
                        .setSubtitle(lowStorageSummary)
                        .addEndItem(icon, ListBuilder.ICON_IMAGE)
                        .setPrimaryAction(primarySliceAction))
        return listBuilder
                .addRow(buildRowBuilder(titleLowStorage, summaryLowStorage, icon))
                .build();
    }

@@ -123,4 +112,21 @@ public class LowStorageSlice implements CustomSliceable {
                MetricsProto.MetricsEvent.SLICE)
                .setClassName(mContext.getPackageName(), SubSettings.class.getName());
    }

    private RowBuilder buildRowBuilder(CharSequence title, String summary, IconCompat icon) {
        final SliceAction primarySliceAction = SliceAction.createDeeplink(
                PendingIntent.getActivity(mContext, 0, getIntent(), 0), icon,
                ListBuilder.ICON_IMAGE, title);

        /**
         * TODO(b/114808204): Contextual Home Page - "Low Storage"
         * Slices doesn't support "Icon on the left" in header. Now we intend to start with Icon
         * right aligned. Will update the icon to left until Slices support it.
         */
        return new RowBuilder()
                .setTitle(title)
                .setSubtitle(summary)
                .addEndItem(icon, ListBuilder.ICON_IMAGE)
                .setPrimaryAction(primarySliceAction);
    }
}
 No newline at end of file
+26 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.settings.homepage.contextualcards.slices;

import static android.app.slice.Slice.HINT_ERROR;

import static com.google.common.truth.Truth.assertThat;

import android.content.Context;
@@ -66,7 +68,7 @@ public class LowStorageSliceTest {

    @Test
    @Config(shadows = ShadowPrivateStorageInfo.class)
    public void getSlice_hasLowStorage_shouldBeCorrectSliceContent() {
    public void getSlice_lowStorage_shouldHaveStorageFreeTitle() {
        ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(10L, 100L));

        final Slice slice = mLowStorageSlice.getSlice();
@@ -77,12 +79,33 @@ public class LowStorageSliceTest {

    @Test
    @Config(shadows = ShadowPrivateStorageInfo.class)
    public void getSlice_hasNoLowStorage_shouldBeNull() {
    public void getSlice_lowStorage_shouldNotHaveErrorHint() {
        ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(10L, 100L));

        final Slice slice = mLowStorageSlice.getSlice();

        assertThat(slice.hasHint(HINT_ERROR)).isFalse();
    }

    @Test
    @Config(shadows = ShadowPrivateStorageInfo.class)
    public void getSlice_storageFree_shouldHaveStorageSettingsTitle() {
        ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(100L, 100L));

        final Slice slice = mLowStorageSlice.getSlice();

        final List<SliceItem> sliceItems = slice.getItems();
        SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_settings));
    }

    @Test
    @Config(shadows = ShadowPrivateStorageInfo.class)
    public void getSlice_storageFree_shouldHaveErrorHint() {
        ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(100L, 100L));

        final Slice slice = mLowStorageSlice.getSlice();

        assertThat(slice).isNull();
        assertThat(slice.hasHint(HINT_ERROR)).isTrue();
    }

    @Implements(PrivateStorageInfo.class)