Home | History | Annotate | Download | only in conversationlist
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.messaging.ui.conversationlist;
     17 
     18 import android.app.Activity;
     19 import android.app.AlertDialog;
     20 import android.app.Fragment;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.Intent;
     24 import android.content.res.Resources;
     25 import android.net.Uri;
     26 import android.os.Bundle;
     27 import android.support.annotation.NonNull;
     28 import android.view.View;
     29 
     30 import com.android.messaging.R;
     31 import com.android.messaging.datamodel.action.DeleteConversationAction;
     32 import com.android.messaging.datamodel.action.UpdateConversationArchiveStatusAction;
     33 import com.android.messaging.datamodel.action.UpdateConversationOptionsAction;
     34 import com.android.messaging.datamodel.action.UpdateDestinationBlockedAction;
     35 import com.android.messaging.datamodel.data.ConversationListData;
     36 import com.android.messaging.datamodel.data.ConversationListItemData;
     37 import com.android.messaging.ui.BugleActionBarActivity;
     38 import com.android.messaging.ui.SnackBar;
     39 import com.android.messaging.ui.SnackBarInteraction;
     40 import com.android.messaging.ui.UIIntents;
     41 import com.android.messaging.ui.contact.AddContactsConfirmationDialog;
     42 import com.android.messaging.ui.conversationlist.ConversationListFragment.ConversationListFragmentHost;
     43 import com.android.messaging.ui.conversationlist.MultiSelectActionModeCallback.SelectedConversation;
     44 import com.android.messaging.util.BugleGservices;
     45 import com.android.messaging.util.BugleGservicesKeys;
     46 import com.android.messaging.util.DebugUtils;
     47 import com.android.messaging.util.PhoneUtils;
     48 import com.android.messaging.util.Trace;
     49 import com.android.messaging.util.UiUtils;
     50 
     51 import java.util.ArrayList;
     52 import java.util.Collection;
     53 import java.util.List;
     54 
     55 import javax.annotation.Nullable;
     56 
     57 /**
     58  * Base class for many Conversation List activities. This will handle the common actions of multi
     59  * select and common launching of intents.
     60  */
     61 public abstract class AbstractConversationListActivity  extends BugleActionBarActivity
     62     implements ConversationListFragmentHost, MultiSelectActionModeCallback.Listener {
     63 
     64     private static final int REQUEST_SET_DEFAULT_SMS_APP = 1;
     65 
     66     protected ConversationListFragment mConversationListFragment;
     67 
     68     @Override
     69     public void onAttachFragment(final Fragment fragment) {
     70         Trace.beginSection("AbstractConversationListActivity.onAttachFragment");
     71         // Fragment could be debug dialog
     72         if (fragment instanceof ConversationListFragment) {
     73             mConversationListFragment = (ConversationListFragment) fragment;
     74             mConversationListFragment.setHost(this);
     75         }
     76         Trace.endSection();
     77     }
     78 
     79     @Override
     80     public void onBackPressed() {
     81         // If action mode is active dismiss it
     82         if (getActionMode() != null) {
     83             dismissActionMode();
     84             return;
     85         }
     86         super.onBackPressed();
     87     }
     88 
     89     protected void startMultiSelectActionMode() {
     90         startActionMode(new MultiSelectActionModeCallback(this));
     91     }
     92 
     93     protected void exitMultiSelectState() {
     94         mConversationListFragment.showFab();
     95         dismissActionMode();
     96         mConversationListFragment.updateUi();
     97     }
     98 
     99     protected boolean isInConversationListSelectMode() {
    100         return getActionModeCallback() instanceof MultiSelectActionModeCallback;
    101     }
    102 
    103     @Override
    104     public boolean isSelectionMode() {
    105         return isInConversationListSelectMode();
    106     }
    107 
    108     @Override
    109     public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    110     }
    111 
    112     @Override
    113     public void onActionBarDelete(final Collection<SelectedConversation> conversations) {
    114         if (!PhoneUtils.getDefault().isDefaultSmsApp()) {
    115             // TODO: figure out a good way to combine this with the implementation in
    116             // ConversationFragment doing similar things
    117             final Activity activity = this;
    118             UiUtils.showSnackBarWithCustomAction(this,
    119                     getWindow().getDecorView().getRootView(),
    120                     getString(R.string.requires_default_sms_app),
    121                     SnackBar.Action.createCustomAction(new Runnable() {
    122                             @Override
    123                             public void run() {
    124                                 final Intent intent =
    125                                         UIIntents.get().getChangeDefaultSmsAppIntent(activity);
    126                                 startActivityForResult(intent, REQUEST_SET_DEFAULT_SMS_APP);
    127                             }
    128                         },
    129                         getString(R.string.requires_default_sms_change_button)),
    130                     null /* interactions */,
    131                     null /* placement */);
    132             return;
    133         }
    134 
    135         new AlertDialog.Builder(this)
    136                 .setTitle(getResources().getQuantityString(
    137                         R.plurals.delete_conversations_confirmation_dialog_title,
    138                         conversations.size()))
    139                 .setPositiveButton(R.string.delete_conversation_confirmation_button,
    140                         new DialogInterface.OnClickListener() {
    141                             @Override
    142                             public void onClick(final DialogInterface dialog,
    143                                     final int button) {
    144                                 for (final SelectedConversation conversation : conversations) {
    145                                     DeleteConversationAction.deleteConversation(
    146                                             conversation.conversationId,
    147                                             conversation.timestamp);
    148                                 }
    149                                 exitMultiSelectState();
    150                             }
    151                 })
    152                 .setNegativeButton(R.string.delete_conversation_decline_button, null)
    153                 .show();
    154     }
    155 
    156     @Override
    157     public void onActionBarArchive(final Iterable<SelectedConversation> conversations,
    158             final boolean isToArchive) {
    159         final ArrayList<String> conversationIds = new ArrayList<String>();
    160         for (final SelectedConversation conversation : conversations) {
    161             final String conversationId = conversation.conversationId;
    162             conversationIds.add(conversationId);
    163             if (isToArchive) {
    164                 UpdateConversationArchiveStatusAction.archiveConversation(conversationId);
    165             } else {
    166                 UpdateConversationArchiveStatusAction.unarchiveConversation(conversationId);
    167             }
    168         }
    169 
    170         final Runnable undoRunnable = new Runnable() {
    171             @Override
    172             public void run() {
    173                 for (final String conversationId : conversationIds) {
    174                     if (isToArchive) {
    175                         UpdateConversationArchiveStatusAction.unarchiveConversation(conversationId);
    176                     } else {
    177                         UpdateConversationArchiveStatusAction.archiveConversation(conversationId);
    178                     }
    179                 }
    180             }
    181         };
    182 
    183         final int textId =
    184                 isToArchive ? R.string.archived_toast_message : R.string.unarchived_toast_message;
    185         final String message = getResources().getString(textId, conversationIds.size());
    186         UiUtils.showSnackBar(this, findViewById(android.R.id.list), message, undoRunnable,
    187                 SnackBar.Action.SNACK_BAR_UNDO,
    188                 mConversationListFragment.getSnackBarInteractions());
    189         exitMultiSelectState();
    190     }
    191 
    192     @Override
    193     public void onActionBarNotification(final Iterable<SelectedConversation> conversations,
    194             final boolean isNotificationOn) {
    195         for (final SelectedConversation conversation : conversations) {
    196             UpdateConversationOptionsAction.enableConversationNotifications(
    197                     conversation.conversationId, isNotificationOn);
    198         }
    199 
    200         final int textId = isNotificationOn ?
    201                 R.string.notification_on_toast_message : R.string.notification_off_toast_message;
    202         final String message = getResources().getString(textId, 1);
    203         UiUtils.showSnackBar(this, findViewById(android.R.id.list), message,
    204             null /* undoRunnable */,
    205             SnackBar.Action.SNACK_BAR_UNDO, mConversationListFragment.getSnackBarInteractions());
    206         exitMultiSelectState();
    207     }
    208 
    209     @Override
    210     public void onActionBarAddContact(final SelectedConversation conversation) {
    211         final Uri avatarUri;
    212         if (conversation.icon != null) {
    213             avatarUri = Uri.parse(conversation.icon);
    214         } else {
    215             avatarUri = null;
    216         }
    217         final AddContactsConfirmationDialog dialog = new AddContactsConfirmationDialog(
    218                 this, avatarUri, conversation.otherParticipantNormalizedDestination);
    219         dialog.show();
    220         exitMultiSelectState();
    221     }
    222 
    223     @Override
    224     public void onActionBarBlock(final SelectedConversation conversation) {
    225         final Resources res = getResources();
    226         new AlertDialog.Builder(this)
    227                 .setTitle(res.getString(R.string.block_confirmation_title,
    228                         conversation.otherParticipantNormalizedDestination))
    229                 .setMessage(res.getString(R.string.block_confirmation_message))
    230                 .setNegativeButton(android.R.string.cancel, null)
    231                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    232                     @Override
    233                     public void onClick(final DialogInterface arg0, final int arg1) {
    234                         final Context context = AbstractConversationListActivity.this;
    235                         final View listView = findViewById(android.R.id.list);
    236                         final List<SnackBarInteraction> interactions =
    237                                 mConversationListFragment.getSnackBarInteractions();
    238                         final UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener
    239                                 undoListener =
    240                                         new UpdateDestinationBlockedActionSnackBar(
    241                                                 context, listView, null /* undoRunnable */,
    242                                                 interactions);
    243                         final Runnable undoRunnable = new Runnable() {
    244                             @Override
    245                             public void run() {
    246                                 UpdateDestinationBlockedAction.updateDestinationBlocked(
    247                                         conversation.otherParticipantNormalizedDestination, false,
    248                                         conversation.conversationId,
    249                                         undoListener);
    250                             }
    251                         };
    252                         final UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener
    253                               listener = new UpdateDestinationBlockedActionSnackBar(
    254                                       context, listView, undoRunnable, interactions);
    255                         UpdateDestinationBlockedAction.updateDestinationBlocked(
    256                                 conversation.otherParticipantNormalizedDestination, true,
    257                                 conversation.conversationId,
    258                                 listener);
    259                         exitMultiSelectState();
    260                     }
    261                 })
    262                 .create()
    263                 .show();
    264     }
    265 
    266     @Override
    267     public void onConversationClick(final ConversationListData listData,
    268                                     final ConversationListItemData conversationListItemData,
    269                                     final boolean isLongClick,
    270                                     final ConversationListItemView conversationView) {
    271         if (isLongClick && !isInConversationListSelectMode()) {
    272             startMultiSelectActionMode();
    273         }
    274 
    275         if (isInConversationListSelectMode()) {
    276             final MultiSelectActionModeCallback multiSelectActionMode =
    277                     (MultiSelectActionModeCallback) getActionModeCallback();
    278             multiSelectActionMode.toggleSelect(listData, conversationListItemData);
    279             mConversationListFragment.updateUi();
    280         } else {
    281             final String conversationId = conversationListItemData.getConversationId();
    282             Bundle sceneTransitionAnimationOptions = null;
    283             boolean hasCustomTransitions = false;
    284 
    285             UIIntents.get().launchConversationActivity(
    286                     this, conversationId, null,
    287                     sceneTransitionAnimationOptions,
    288                     hasCustomTransitions);
    289         }
    290     }
    291 
    292     @Override
    293     public void onCreateConversationClick() {
    294         UIIntents.get().launchCreateNewConversationActivity(this, null);
    295     }
    296 
    297 
    298     @Override
    299     public boolean isConversationSelected(final String conversationId) {
    300         return isInConversationListSelectMode() &&
    301                 ((MultiSelectActionModeCallback) getActionModeCallback()).isSelected(
    302                         conversationId);
    303     }
    304 
    305     public void onActionBarDebug() {
    306         DebugUtils.showDebugOptions(this);
    307     }
    308 
    309     private static class UpdateDestinationBlockedActionSnackBar
    310             implements UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener {
    311         private final Context mContext;
    312         private final View mParentView;
    313         private final Runnable mUndoRunnable;
    314         private final List<SnackBarInteraction> mInteractions;
    315 
    316         UpdateDestinationBlockedActionSnackBar(final Context context,
    317                 @NonNull final View parentView, @Nullable final Runnable undoRunnable,
    318                 @Nullable List<SnackBarInteraction> interactions) {
    319             mContext = context;
    320             mParentView = parentView;
    321             mUndoRunnable = undoRunnable;
    322             mInteractions = interactions;
    323         }
    324 
    325         @Override
    326         public void onUpdateDestinationBlockedAction(
    327             final UpdateDestinationBlockedAction action,
    328             final boolean success, final boolean block,
    329             final String destination) {
    330             if (success) {
    331                 final int messageId = block ? R.string.blocked_toast_message
    332                         : R.string.unblocked_toast_message;
    333                 final String message = mContext.getResources().getString(messageId, 1);
    334                 UiUtils.showSnackBar(mContext, mParentView, message, mUndoRunnable,
    335                         SnackBar.Action.SNACK_BAR_UNDO, mInteractions);
    336             }
    337         }
    338     }
    339 }
    340