Bug: 301395074 Test: atest SettingsRoboTests:com.android.settings.localepicker Change-Id: Ic771cd5146ab954c3da65748bf87cd14d30770b4
183 lines
7.0 KiB
Java
183 lines
7.0 KiB
Java
/*
|
|
* 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
|
|
*
|
|
* 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.localepicker;
|
|
|
|
import android.content.Context;
|
|
import android.os.SystemClock;
|
|
import android.os.SystemProperties;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.VisibleForTesting;
|
|
|
|
import java.util.Calendar;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* A controller that evaluates whether the notification can be triggered and update the
|
|
* SharedPreference.
|
|
*/
|
|
public class NotificationController {
|
|
private static final String TAG = NotificationController.class.getSimpleName();
|
|
private static final int DISMISS_COUNT_THRESHOLD = 2;
|
|
private static final int NOTIFICATION_COUNT_THRESHOLD = 2;
|
|
private static final int MULTIPLE_BASE = 2;
|
|
// seven days: 7 * 24 * 60
|
|
private static final int MIN_DURATION_BETWEEN_NOTIFICATIONS_MIN = 10080;
|
|
private static final String PROPERTY_MIN_DURATION =
|
|
"android.localenotification.duration.threshold";
|
|
|
|
private static NotificationController sInstance = null;
|
|
|
|
private final LocaleNotificationDataManager mDataManager;
|
|
|
|
/**
|
|
* Get {@link NotificationController} instance.
|
|
*
|
|
* @param context The context
|
|
* @return {@link NotificationController} instance
|
|
*/
|
|
public static synchronized NotificationController getInstance(@NonNull Context context) {
|
|
if (sInstance == null) {
|
|
sInstance = new NotificationController(context);
|
|
}
|
|
return sInstance;
|
|
}
|
|
|
|
private NotificationController(Context context) {
|
|
mDataManager = new LocaleNotificationDataManager(context);
|
|
}
|
|
|
|
@VisibleForTesting
|
|
LocaleNotificationDataManager getDataManager() {
|
|
return mDataManager;
|
|
}
|
|
|
|
/**
|
|
* Increment the dismissCount of the notification.
|
|
*
|
|
* @param locale A locale used to query the {@link NotificationInfo}
|
|
*/
|
|
public void incrementDismissCount(@NonNull String locale) {
|
|
NotificationInfo currentInfo = mDataManager.getNotificationInfo(locale);
|
|
NotificationInfo newInfo = new NotificationInfo(currentInfo.getUidCollection(),
|
|
currentInfo.getNotificationCount(),
|
|
currentInfo.getDismissCount() + 1,
|
|
currentInfo.getLastNotificationTimeMs(),
|
|
currentInfo.getNotificationId());
|
|
mDataManager.putNotificationInfo(locale, newInfo);
|
|
}
|
|
|
|
/**
|
|
* Whether the notification can be triggered or not.
|
|
*
|
|
* @param uid The application's uid.
|
|
* @param locale The application's locale which the user updated to.
|
|
* @return true if the notification needs to be triggered. Otherwise, false.
|
|
*/
|
|
public boolean shouldTriggerNotification(int uid, @NonNull String locale) {
|
|
if (LocaleUtils.isInSystemLocale(locale)) {
|
|
return false;
|
|
} else {
|
|
// Add the uid into the locale's uid list and update the notification count if the
|
|
// notification can be triggered.
|
|
return updateLocaleNotificationInfo(uid, locale);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the notification id
|
|
*
|
|
* @param locale The locale which the application sets to
|
|
* @return the notification id
|
|
*/
|
|
public int getNotificationId(@NonNull String locale) {
|
|
NotificationInfo info = mDataManager.getNotificationInfo(locale);
|
|
return (info != null) ? info.getNotificationId() : -1;
|
|
}
|
|
|
|
/**
|
|
* Remove the {@link NotificationInfo} with the corresponding locale
|
|
*
|
|
* @param locale The locale which the application sets to
|
|
*/
|
|
public void removeNotificationInfo(@NonNull String locale) {
|
|
mDataManager.removeNotificationInfo(locale);
|
|
}
|
|
|
|
private boolean updateLocaleNotificationInfo(int uid, String locale) {
|
|
NotificationInfo info = mDataManager.getNotificationInfo(locale);
|
|
if (info == null) {
|
|
// Create an empty record with the uid and update the SharedPreference.
|
|
NotificationInfo emptyInfo = new NotificationInfo(Set.of(uid), 0, 0, 0, 0);
|
|
mDataManager.putNotificationInfo(locale, emptyInfo);
|
|
return false;
|
|
}
|
|
Set uidCollection = info.getUidCollection();
|
|
if (uidCollection.contains(uid)) {
|
|
return false;
|
|
}
|
|
|
|
NotificationInfo newInfo =
|
|
createNotificationInfoWithNewUidAndCount(uidCollection, uid, info);
|
|
mDataManager.putNotificationInfo(locale, newInfo);
|
|
return newInfo.getNotificationCount() > info.getNotificationCount();
|
|
}
|
|
|
|
private NotificationInfo createNotificationInfoWithNewUidAndCount(
|
|
Set<Integer> uidSet, int uid, NotificationInfo info) {
|
|
int dismissCount = info.getDismissCount();
|
|
int notificationCount = info.getNotificationCount();
|
|
long lastNotificationTime = info.getLastNotificationTimeMs();
|
|
int notificationId = info.getNotificationId();
|
|
if (dismissCount < DISMISS_COUNT_THRESHOLD
|
|
&& notificationCount < NOTIFICATION_COUNT_THRESHOLD) {
|
|
// Add the uid into the locale's uid list
|
|
uidSet.add(uid);
|
|
// Notification should fire on multiples of 2 apps using the locale.
|
|
if (uidSet.size() % MULTIPLE_BASE == 0
|
|
&& !isNotificationFrequent(lastNotificationTime)) {
|
|
// Increment the count because the notification can be triggered.
|
|
notificationCount = info.getNotificationCount() + 1;
|
|
lastNotificationTime = Calendar.getInstance().getTimeInMillis();
|
|
Log.i(TAG, "notificationCount:" + notificationCount);
|
|
if (notificationCount == 1) {
|
|
notificationId = (int) SystemClock.uptimeMillis();
|
|
}
|
|
}
|
|
}
|
|
return new NotificationInfo(uidSet, notificationCount, dismissCount, lastNotificationTime,
|
|
notificationId);
|
|
}
|
|
|
|
/**
|
|
* Evaluates if the notification is triggered frequently.
|
|
*
|
|
* @param lastNotificationTime The timestamp that the last notification was triggered.
|
|
* @return true if the duration of the two continuous notifications is smaller than the
|
|
* threshold.
|
|
* Otherwise, false.
|
|
*/
|
|
private boolean isNotificationFrequent(long lastNotificationTime) {
|
|
Calendar time = Calendar.getInstance();
|
|
int threshold = SystemProperties.getInt(PROPERTY_MIN_DURATION,
|
|
MIN_DURATION_BETWEEN_NOTIFICATIONS_MIN);
|
|
time.add(Calendar.MINUTE, threshold * -1);
|
|
return time.getTimeInMillis() < lastNotificationTime;
|
|
}
|
|
}
|