1 /*
2  * Copyright (C) 2017 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 
17 package com.android.dialer.calllog;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.support.v4.content.LocalBroadcastManager;
22 import com.android.dialer.calllog.datasources.CallLogDataSource;
23 import com.android.dialer.calllog.datasources.DataSources;
24 import com.android.dialer.common.LogUtil;
25 import com.android.dialer.common.concurrent.Annotations.Ui;
26 import com.android.dialer.inject.ApplicationContext;
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import com.google.common.util.concurrent.ListeningExecutorService;
30 import com.google.common.util.concurrent.MoreExecutors;
31 import java.util.ArrayList;
32 import java.util.List;
33 import javax.inject.Inject;
34 import javax.inject.Singleton;
35 
36 /**
37  * Coordinates work across {@link DataSources}.
38  *
39  * <p>All methods should be called on the main thread.
40  */
41 @Singleton
42 public final class CallLogFramework {
43 
44   private final Context appContext;
45   private final DataSources dataSources;
46   private final AnnotatedCallLogMigrator annotatedCallLogMigrator;
47   private final ListeningExecutorService uiExecutor;
48   private final CallLogState callLogState;
49 
50   @Inject
CallLogFramework( @pplicationContext Context appContext, DataSources dataSources, AnnotatedCallLogMigrator annotatedCallLogMigrator, @Ui ListeningExecutorService uiExecutor, CallLogState callLogState)51   CallLogFramework(
52       @ApplicationContext Context appContext,
53       DataSources dataSources,
54       AnnotatedCallLogMigrator annotatedCallLogMigrator,
55       @Ui ListeningExecutorService uiExecutor,
56       CallLogState callLogState) {
57     this.appContext = appContext;
58     this.dataSources = dataSources;
59     this.annotatedCallLogMigrator = annotatedCallLogMigrator;
60     this.uiExecutor = uiExecutor;
61     this.callLogState = callLogState;
62   }
63 
64   /** Registers the content observers for all data sources. */
registerContentObservers()65   public void registerContentObservers() {
66     LogUtil.enterBlock("CallLogFramework.registerContentObservers");
67     for (CallLogDataSource dataSource : dataSources.getDataSourcesIncludingSystemCallLog()) {
68       dataSource.registerContentObservers();
69     }
70   }
71 
72   /** Enables the framework. */
enable()73   public ListenableFuture<Void> enable() {
74     registerContentObservers();
75     return annotatedCallLogMigrator.migrate();
76   }
77 
78   /** Disables the framework. */
disable()79   public ListenableFuture<Void> disable() {
80     return Futures.transform(
81         Futures.allAsList(disableDataSources(), annotatedCallLogMigrator.clearData()),
82         unused -> null,
83         MoreExecutors.directExecutor());
84   }
85 
disableDataSources()86   private ListenableFuture<Void> disableDataSources() {
87     LogUtil.enterBlock("CallLogFramework.disableDataSources");
88 
89     for (CallLogDataSource dataSource : dataSources.getDataSourcesIncludingSystemCallLog()) {
90       dataSource.unregisterContentObservers();
91     }
92 
93     callLogState.clearData();
94 
95     // Clear data only after all content observers have been disabled.
96     List<ListenableFuture<Void>> allFutures = new ArrayList<>();
97     for (CallLogDataSource dataSource : dataSources.getDataSourcesIncludingSystemCallLog()) {
98       allFutures.add(dataSource.clearData());
99     }
100 
101     return Futures.transform(
102         Futures.allAsList(allFutures),
103         unused -> {
104           // Send a broadcast to the OldMainActivityPeer to remove the NewCallLogFragment and
105           // NewVoicemailFragment if it is currently attached. If this is not done, user interaction
106           // with the fragment could cause call log framework state to be unexpectedly written. For
107           // example scrolling could cause the AnnotatedCallLog to be read (which would trigger
108           // database creation).
109           LocalBroadcastManager.getInstance(appContext)
110               .sendBroadcastSync(new Intent("disableCallLogFramework"));
111           return null;
112         },
113         uiExecutor);
114   }
115 }
116