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

Commit b67c157e authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge "Move ZenModesBackend to SettingsLib." into main

parents 4d8c8faa b1dad7d5
Loading
Loading
Loading
Loading
+0 −28
Original line number Diff line number Diff line
<!--
    Copyright (C) 2018 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="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0"
        android:tint="?android:attr/colorControlNormal">
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M7,11h10v2h-10z"/>
</vector>
+2 −1
Original line number Diff line number Diff line
@@ -105,7 +105,8 @@ public class DndConditionCardController implements ConditionalCardController {
                        + mAppContext.getText(R.string.condition_zen_title))
                .setTitleText(mAppContext.getText(R.string.condition_zen_title).toString())
                .setSummaryText(getSummary())
                .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
                .setIconDrawable(mAppContext.getDrawable(
                        com.android.settingslib.R.drawable.ic_do_not_disturb_on_24dp))
                .setViewType(ConditionContextualCardRenderer.VIEW_TYPE_HALF_WIDTH)
                .build();
    }
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import androidx.annotation.Nullable;
import androidx.preference.Preference;

import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;

import com.google.common.base.Preconditions;

+0 −161
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.
 */

package com.android.settings.notification.modes;

import static com.google.common.util.concurrent.Futures.immediateFuture;

import static java.util.Objects.requireNonNull;

import android.annotation.Nullable;
import android.app.AutomaticZenRule;
import android.content.Context;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.service.notification.SystemZenRules;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.content.res.AppCompatResources;

import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class IconLoader {

    private static final String TAG = "ZenIconLoader";

    private static final Drawable MISSING = new ColorDrawable();

    @Nullable // Until first usage
    private static IconLoader sInstance;

    private final LruCache<String, Drawable> mCache;
    private final ListeningExecutorService mBackgroundExecutor;

    static IconLoader getInstance() {
        if (sInstance == null) {
            sInstance = new IconLoader();
        }
        return sInstance;
    }

    private IconLoader() {
        this(Executors.newFixedThreadPool(4));
    }

    @VisibleForTesting
    IconLoader(ExecutorService backgroundExecutor) {
        mCache = new LruCache<>(50);
        mBackgroundExecutor =
                MoreExecutors.listeningDecorator(backgroundExecutor);
    }

    @NonNull
    ListenableFuture<Drawable> getIcon(Context context, @NonNull AutomaticZenRule rule) {
        if (rule.getIconResId() == 0) {
            return Futures.immediateFuture(getFallbackIcon(context, rule.getType()));
        }

        return FluentFuture.from(loadIcon(context, rule.getPackageName(), rule.getIconResId()))
                .transform(icon ->
                        icon != null ? icon : getFallbackIcon(context, rule.getType()),
                        MoreExecutors.directExecutor());
    }

    @NonNull
    private ListenableFuture</* @Nullable */ Drawable> loadIcon(Context context, String pkg,
            int iconResId) {
        String cacheKey = pkg + ":" + iconResId;
        synchronized (mCache) {
            Drawable cachedValue = mCache.get(cacheKey);
            if (cachedValue != null) {
                return immediateFuture(cachedValue != MISSING ? cachedValue : null);
            }
        }

        return FluentFuture.from(mBackgroundExecutor.submit(() -> {
            if (TextUtils.isEmpty(pkg) || SystemZenRules.PACKAGE_ANDROID.equals(pkg)) {
                return context.getDrawable(iconResId);
            } else {
                Context appContext = context.createPackageContext(pkg, 0);
                Drawable appDrawable = AppCompatResources.getDrawable(appContext, iconResId);
                return getMonochromeIconIfPresent(appDrawable);
            }
        })).catching(Exception.class, ex -> {
            // If we cannot resolve the icon, then store MISSING in the cache below, so
            // we don't try again.
            Log.e(TAG, "Error while loading icon " + cacheKey, ex);
            return null;
        }, MoreExecutors.directExecutor()).transform(drawable -> {
            synchronized (mCache) {
                mCache.put(cacheKey, drawable != null ? drawable : MISSING);
            }
            return drawable;
        }, MoreExecutors.directExecutor());
    }

    private static Drawable getFallbackIcon(Context context, int ruleType) {
        int iconResIdFromType = switch (ruleType) {
            case AutomaticZenRule.TYPE_UNKNOWN ->
                    com.android.internal.R.drawable.ic_zen_mode_type_unknown;
            case AutomaticZenRule.TYPE_OTHER ->
                    com.android.internal.R.drawable.ic_zen_mode_type_other;
            case AutomaticZenRule.TYPE_SCHEDULE_TIME ->
                    com.android.internal.R.drawable.ic_zen_mode_type_schedule_time;
            case AutomaticZenRule.TYPE_SCHEDULE_CALENDAR ->
                    com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar;
            case AutomaticZenRule.TYPE_BEDTIME ->
                    com.android.internal.R.drawable.ic_zen_mode_type_bedtime;
            case AutomaticZenRule.TYPE_DRIVING ->
                    com.android.internal.R.drawable.ic_zen_mode_type_driving;
            case AutomaticZenRule.TYPE_IMMERSIVE ->
                    com.android.internal.R.drawable.ic_zen_mode_type_immersive;
            case AutomaticZenRule.TYPE_THEATER ->
                    com.android.internal.R.drawable.ic_zen_mode_type_theater;
            case AutomaticZenRule.TYPE_MANAGED ->
                    com.android.internal.R.drawable.ic_zen_mode_type_managed;
            default ->
                    com.android.internal.R.drawable.ic_zen_mode_type_unknown;
        };
        return requireNonNull(context.getDrawable(iconResIdFromType));
    }

    private static Drawable getMonochromeIconIfPresent(Drawable icon) {
        // For created rules, the app should've provided a monochrome Drawable. However, implicit
        // rules have the app's icon, which is not -- but might have a monochrome layer. Thus
        // we choose it, if present.
        if (icon instanceof AdaptiveIconDrawable adaptiveIcon) {
            if (adaptiveIcon.getMonochrome() != null) {
                // Wrap with negative inset => scale icon (inspired from BaseIconFactory)
                return new InsetDrawable(adaptiveIcon.getMonochrome(),
                        -2.0f * AdaptiveIconDrawable.getExtraInsetFraction());
            }
        }
        return icon;
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;

import com.android.settings.R;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;

class InterruptionFilterPreferenceController extends AbstractZenModePreferenceController
        implements Preference.OnPreferenceChangeListener {
Loading