123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- * Nextcloud Android client application
- *
- * @author Mario Danic
- * @author Andy Scherzinger
- * @author Chris Narkiewicz
- * Copyright (C) 2018 Mario Danic
- * Copyright (C) 2018 Andy Scherzinger
- * Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.owncloud.android.jobs;
- import android.app.Activity;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.BroadcastReceiver;
- import android.content.ContentResolver;
- import android.content.Context;
- import android.content.Intent;
- import android.graphics.BitmapFactory;
- import android.media.RingtoneManager;
- import android.text.TextUtils;
- import com.evernote.android.job.Job;
- import com.google.gson.Gson;
- import com.nextcloud.client.account.User;
- import com.nextcloud.client.account.UserAccountManager;
- import com.nextcloud.client.core.Clock;
- import com.nextcloud.client.preferences.AppPreferences;
- import com.nextcloud.client.preferences.AppPreferencesImpl;
- import com.owncloud.android.R;
- import com.owncloud.android.datamodel.ArbitraryDataProvider;
- import com.owncloud.android.datamodel.MediaFolder;
- import com.owncloud.android.datamodel.MediaFoldersModel;
- import com.owncloud.android.datamodel.MediaProvider;
- import com.owncloud.android.datamodel.SyncedFolder;
- import com.owncloud.android.datamodel.SyncedFolderProvider;
- import com.owncloud.android.lib.common.utils.Log_OC;
- import com.owncloud.android.ui.activity.ManageAccountsActivity;
- import com.owncloud.android.ui.activity.SyncedFoldersActivity;
- import com.owncloud.android.ui.notifications.NotificationUtils;
- import com.owncloud.android.utils.ThemeUtils;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import androidx.annotation.NonNull;
- import androidx.core.app.NotificationCompat;
- import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
- @SuppressFBWarnings(value = "PREDICTABLE_RANDOM", justification = "Only used for notification id.")
- public class MediaFoldersDetectionJob extends Job {
- public static final String TAG = "MediaFoldersDetectionJob";
- public static final String KEY_MEDIA_FOLDER_PATH = "KEY_MEDIA_FOLDER_PATH";
- public static final String KEY_MEDIA_FOLDER_TYPE = "KEY_MEDIA_FOLDER_TYPE";
- private static final String ACCOUNT_NAME_GLOBAL = "global";
- private static final String KEY_MEDIA_FOLDERS = "media_folders";
- public static final String NOTIFICATION_ID = "NOTIFICATION_ID";
- private static final String DISABLE_DETECTION_CLICK = "DISABLE_DETECTION_CLICK";
- private final UserAccountManager userAccountManager;
- private final Clock clock;
- private final Random randomId = new Random();
- MediaFoldersDetectionJob(UserAccountManager accountManager, Clock clock) {
- this.userAccountManager = accountManager;
- this.clock = clock;
- }
- @NonNull
- @Override
- protected Result onRunJob(@NonNull Params params) {
- Context context = getContext();
- ContentResolver contentResolver = context.getContentResolver();
- ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);
- SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver,
- AppPreferencesImpl.fromContext(context),
- clock);
- Gson gson = new Gson();
- String arbitraryDataString;
- MediaFoldersModel mediaFoldersModel;
- List<MediaFolder> imageMediaFolders = MediaProvider.getImageFolders(contentResolver, 1, null, true);
- List<MediaFolder> videoMediaFolders = MediaProvider.getVideoFolders(contentResolver, 1, null, true);
- List<String> imageMediaFolderPaths = new ArrayList<>();
- List<String> videoMediaFolderPaths = new ArrayList<>();
- for (MediaFolder imageMediaFolder : imageMediaFolders) {
- imageMediaFolderPaths.add(imageMediaFolder.absolutePath);
- }
- for (MediaFolder videoMediaFolder : videoMediaFolders) {
- imageMediaFolderPaths.add(videoMediaFolder.absolutePath);
- }
- arbitraryDataString = arbitraryDataProvider.getValue(ACCOUNT_NAME_GLOBAL, KEY_MEDIA_FOLDERS);
- if (!TextUtils.isEmpty(arbitraryDataString)) {
- mediaFoldersModel = gson.fromJson(arbitraryDataString, MediaFoldersModel.class);
- // merge new detected paths with already notified ones
- for (String existingImageFolderPath : mediaFoldersModel.getImageMediaFolders()) {
- if (!imageMediaFolderPaths.contains(existingImageFolderPath)) {
- imageMediaFolderPaths.add(existingImageFolderPath);
- }
- }
- for (String existingVideoFolderPath : mediaFoldersModel.getVideoMediaFolders()) {
- if (!videoMediaFolderPaths.contains(existingVideoFolderPath)) {
- videoMediaFolderPaths.add(existingVideoFolderPath);
- }
- }
- // Store updated values
- arbitraryDataProvider.storeOrUpdateKeyValue(ACCOUNT_NAME_GLOBAL, KEY_MEDIA_FOLDERS, gson.toJson(new
- MediaFoldersModel(imageMediaFolderPaths, videoMediaFolderPaths)));
- final AppPreferences preferences = AppPreferencesImpl.fromContext(getContext());
- if (preferences.isShowMediaScanNotifications()) {
- imageMediaFolderPaths.removeAll(mediaFoldersModel.getImageMediaFolders());
- videoMediaFolderPaths.removeAll(mediaFoldersModel.getVideoMediaFolders());
- if (!imageMediaFolderPaths.isEmpty() || !videoMediaFolderPaths.isEmpty()) {
- List<User> allUsers = userAccountManager.getAllUsers();
- List<User> activeUsers = new ArrayList<>();
- for (User account : allUsers) {
- if (!arbitraryDataProvider.getBooleanValue(account.toPlatformAccount(),
- ManageAccountsActivity.PENDING_FOR_REMOVAL)) {
- activeUsers.add(account);
- }
- }
- for (User user : activeUsers) {
- for (String imageMediaFolder : imageMediaFolderPaths) {
- final SyncedFolder folder = syncedFolderProvider.findByLocalPathAndAccount(imageMediaFolder,
- user.toPlatformAccount());
- if (folder == null) {
- String contentTitle = String.format(context.getString(R.string.new_media_folder_detected),
- context.getString(R.string.new_media_folder_photos));
- sendNotification(contentTitle,
- imageMediaFolder.substring(imageMediaFolder.lastIndexOf('/') + 1),
- user,
- imageMediaFolder,
- 1);
- }
- }
- for (String videoMediaFolder : videoMediaFolderPaths) {
- final SyncedFolder folder = syncedFolderProvider.findByLocalPathAndAccount(videoMediaFolder,
- user.toPlatformAccount());
- if (folder == null) {
- String contentTitle = String.format(context.getString(R.string.new_media_folder_detected),
- context.getString(R.string.new_media_folder_videos));
- sendNotification(contentTitle,
- videoMediaFolder.substring(videoMediaFolder.lastIndexOf('/') + 1),
- user,
- videoMediaFolder,
- 2);
- }
- }
- }
- }
- }
- } else {
- mediaFoldersModel = new MediaFoldersModel(imageMediaFolderPaths, videoMediaFolderPaths);
- arbitraryDataProvider.storeOrUpdateKeyValue(ACCOUNT_NAME_GLOBAL, KEY_MEDIA_FOLDERS,
- gson.toJson(mediaFoldersModel));
- }
- return Result.SUCCESS;
- }
- private void sendNotification(String contentTitle, String subtitle, User user, String path, int type) {
- int notificationId = randomId.nextInt();
- Context context = getContext();
- Intent intent = new Intent(getContext(), SyncedFoldersActivity.class);
- intent.putExtra(NOTIFICATION_ID, notificationId);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(NotificationJob.KEY_NOTIFICATION_ACCOUNT, user.getAccountName());
- intent.putExtra(KEY_MEDIA_FOLDER_PATH, path);
- intent.putExtra(KEY_MEDIA_FOLDER_TYPE, type);
- intent.putExtra(SyncedFoldersActivity.EXTRA_SHOW_SIDEBAR, true);
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
- NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
- context, NotificationUtils.NOTIFICATION_CHANNEL_GENERAL)
- .setSmallIcon(R.drawable.notification_icon)
- .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.notification_icon))
- .setColor(ThemeUtils.primaryColor(getContext()))
- .setSubText(user.getAccountName())
- .setContentTitle(contentTitle)
- .setContentText(subtitle)
- .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
- .setAutoCancel(true)
- .setContentIntent(pendingIntent);
- Intent disableDetection = new Intent(context, NotificationReceiver.class);
- disableDetection.putExtra(NOTIFICATION_ID, notificationId);
- disableDetection.setAction(DISABLE_DETECTION_CLICK);
- PendingIntent disableIntent = PendingIntent.getBroadcast(
- context,
- notificationId,
- disableDetection,
- PendingIntent.FLAG_CANCEL_CURRENT
- );
- notificationBuilder.addAction(
- new NotificationCompat.Action(
- R.drawable.ic_close,
- context.getString(R.string.disable_new_media_folder_detection_notifications),
- disableIntent
- )
- );
- PendingIntent configureIntent = PendingIntent.getActivity(
- context,
- notificationId,
- intent,
- PendingIntent.FLAG_CANCEL_CURRENT
- );
- notificationBuilder.addAction(
- new NotificationCompat.Action(
- R.drawable.ic_settings,
- context.getString(R.string.configure_new_media_folder_detection_notifications),
- configureIntent
- )
- );
- NotificationManager notificationManager = (NotificationManager)
- context.getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager != null) {
- notificationManager.notify(notificationId, notificationBuilder.build());
- }
- }
- public static class NotificationReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- int notificationId = intent.getIntExtra(NOTIFICATION_ID, 0);
- final AppPreferences preferences = AppPreferencesImpl.fromContext(context);
- if (DISABLE_DETECTION_CLICK.equals(action)) {
- Log_OC.d(this, "Disable media scan notifications");
- preferences.setShowMediaScanNotifications(false);
- cancel(context, notificationId);
- }
- }
- private void cancel(Context context, int notificationId) {
- NotificationManager notificationManager =
- (NotificationManager) context.getSystemService(Activity.NOTIFICATION_SERVICE);
- notificationManager.cancel(notificationId);
- }
- }
- }
|