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
17package com.android.messaging;
18
19import android.content.Context;
20import android.os.Process;
21import android.telephony.SmsManager;
22import android.util.SparseArray;
23
24import com.android.messaging.datamodel.DataModel;
25import com.android.messaging.datamodel.DataModelImpl;
26import com.android.messaging.datamodel.MemoryCacheManager;
27import com.android.messaging.datamodel.ParticipantRefresh.ContactContentObserver;
28import com.android.messaging.datamodel.data.ParticipantData;
29import com.android.messaging.datamodel.media.BugleMediaCacheManager;
30import com.android.messaging.datamodel.media.MediaCacheManager;
31import com.android.messaging.datamodel.media.MediaResourceManager;
32import com.android.messaging.sms.BugleCarrierConfigValuesLoader;
33import com.android.messaging.ui.UIIntents;
34import com.android.messaging.ui.UIIntentsImpl;
35import com.android.messaging.util.Assert;
36import com.android.messaging.util.BugleApplicationPrefs;
37import com.android.messaging.util.BugleGservices;
38import com.android.messaging.util.BugleGservicesImpl;
39import com.android.messaging.util.BuglePrefs;
40import com.android.messaging.util.BugleSubscriptionPrefs;
41import com.android.messaging.util.BugleWidgetPrefs;
42import com.android.messaging.util.LogUtil;
43import com.android.messaging.util.MediaUtil;
44import com.android.messaging.util.MediaUtilImpl;
45import com.android.messaging.util.OsUtil;
46import com.android.messaging.util.PhoneUtils;
47
48import java.util.concurrent.ConcurrentHashMap;
49
50class FactoryImpl extends Factory {
51    private BugleApplication mApplication;
52    private DataModel mDataModel;
53    private BugleGservices mBugleGservices;
54    private BugleApplicationPrefs mBugleApplicationPrefs;
55    private BugleWidgetPrefs mBugleWidgetPrefs;
56    private Context mApplicationContext;
57    private UIIntents mUIIntents;
58    private MemoryCacheManager mMemoryCacheManager;
59    private MediaResourceManager mMediaResourceManager;
60    private MediaCacheManager mMediaCacheManager;
61    private ContactContentObserver mContactContentObserver;
62    private PhoneUtils mPhoneUtils;
63    private MediaUtil mMediaUtil;
64    private SparseArray<BugleSubscriptionPrefs> mSubscriptionPrefs;
65    private BugleCarrierConfigValuesLoader mCarrierConfigValuesLoader;
66
67    // Cached instance for Pre-L_MR1
68    private static final Object PHONEUTILS_INSTANCE_LOCK = new Object();
69    private static PhoneUtils sPhoneUtilsInstancePreLMR1 = null;
70    // Cached subId->instance for L_MR1 and beyond
71    private static final ConcurrentHashMap<Integer, PhoneUtils> sPhoneUtilsInstanceCacheLMR1 =
72            new ConcurrentHashMap<>();
73
74    private FactoryImpl() {
75    }
76
77    public static Factory register(final Context applicationContext,
78            final BugleApplication application) {
79        // This only gets called once (from BugleApplication.onCreate), but its not called in tests.
80        Assert.isTrue(!sRegistered);
81        Assert.isNull(Factory.get());
82
83        final FactoryImpl factory = new FactoryImpl();
84        Factory.setInstance(factory);
85        sRegistered = true;
86
87        // At this point Factory is published. Services can now get initialized and depend on
88        // Factory.get().
89        factory.mApplication = application;
90        factory.mApplicationContext = applicationContext;
91        factory.mMemoryCacheManager = new MemoryCacheManager();
92        factory.mMediaCacheManager = new BugleMediaCacheManager();
93        factory.mMediaResourceManager = new MediaResourceManager();
94        factory.mBugleGservices = new BugleGservicesImpl(applicationContext);
95        factory.mBugleApplicationPrefs = new BugleApplicationPrefs(applicationContext);
96        factory.mDataModel = new DataModelImpl(applicationContext);
97        factory.mBugleWidgetPrefs = new BugleWidgetPrefs(applicationContext);
98        factory.mUIIntents = new UIIntentsImpl();
99        factory.mContactContentObserver = new ContactContentObserver();
100        factory.mMediaUtil = new MediaUtilImpl();
101        factory.mSubscriptionPrefs = new SparseArray<BugleSubscriptionPrefs>();
102        factory.mCarrierConfigValuesLoader = new BugleCarrierConfigValuesLoader(applicationContext);
103
104        Assert.initializeGservices(factory.mBugleGservices);
105        LogUtil.initializeGservices(factory.mBugleGservices);
106
107        if (OsUtil.hasRequiredPermissions()) {
108            factory.onRequiredPermissionsAcquired();
109        }
110
111        return factory;
112    }
113
114    @Override
115    public void onRequiredPermissionsAcquired() {
116        if (sInitialized) {
117            return;
118        }
119        sInitialized = true;
120
121        mApplication.initializeSync(this);
122
123        final Thread asyncInitialization = new Thread() {
124            @Override
125            public void run() {
126                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
127                mApplication.initializeAsync(FactoryImpl.this);
128            }
129        };
130        asyncInitialization.start();
131    }
132
133    @Override
134    public Context getApplicationContext() {
135        return mApplicationContext;
136    }
137
138    @Override
139    public DataModel getDataModel() {
140        return mDataModel;
141    }
142
143    @Override
144    public BugleGservices getBugleGservices() {
145        return mBugleGservices;
146    }
147
148    @Override
149    public BuglePrefs getApplicationPrefs() {
150        return mBugleApplicationPrefs;
151    }
152
153    @Override
154    public BuglePrefs getWidgetPrefs() {
155        return mBugleWidgetPrefs;
156    }
157
158    @Override
159    public BuglePrefs getSubscriptionPrefs(int subId) {
160        subId = PhoneUtils.getDefault().getEffectiveSubId(subId);
161        BugleSubscriptionPrefs pref = mSubscriptionPrefs.get(subId);
162        if (pref == null) {
163            synchronized (this) {
164                if ((pref = mSubscriptionPrefs.get(subId)) == null) {
165                    pref = new BugleSubscriptionPrefs(getApplicationContext(), subId);
166                    mSubscriptionPrefs.put(subId, pref);
167                }
168            }
169        }
170        return pref;
171    }
172
173    @Override
174    public UIIntents getUIIntents() {
175        return mUIIntents;
176    }
177
178    @Override
179    public MemoryCacheManager getMemoryCacheManager() {
180        return mMemoryCacheManager;
181    }
182
183    @Override
184    public MediaResourceManager getMediaResourceManager() {
185        return mMediaResourceManager;
186    }
187
188    @Override
189    public MediaCacheManager getMediaCacheManager() {
190        return mMediaCacheManager;
191    }
192
193    @Override
194    public ContactContentObserver getContactContentObserver() {
195        return mContactContentObserver;
196    }
197
198    @Override
199    public PhoneUtils getPhoneUtils(int subId) {
200        if (OsUtil.isAtLeastL_MR1()) {
201            if (subId == ParticipantData.DEFAULT_SELF_SUB_ID) {
202                subId = SmsManager.getDefaultSmsSubscriptionId();
203            }
204            if (subId < 0) {
205                LogUtil.w(LogUtil.BUGLE_TAG, "PhoneUtils.getForLMR1(): invalid subId = " + subId);
206                subId = ParticipantData.DEFAULT_SELF_SUB_ID;
207            }
208            PhoneUtils instance = sPhoneUtilsInstanceCacheLMR1.get(subId);
209            if (instance == null) {
210                instance = new PhoneUtils.PhoneUtilsLMR1(subId);
211                sPhoneUtilsInstanceCacheLMR1.putIfAbsent(subId, instance);
212            }
213            return instance;
214        } else {
215            Assert.isTrue(subId == ParticipantData.DEFAULT_SELF_SUB_ID);
216            if (sPhoneUtilsInstancePreLMR1 == null) {
217                synchronized (PHONEUTILS_INSTANCE_LOCK) {
218                    if (sPhoneUtilsInstancePreLMR1 == null) {
219                        sPhoneUtilsInstancePreLMR1 = new PhoneUtils.PhoneUtilsPreLMR1();
220                    }
221                }
222            }
223            return sPhoneUtilsInstancePreLMR1;
224        }
225    }
226
227    @Override
228    public void reclaimMemory() {
229        mMemoryCacheManager.reclaimMemory();
230    }
231
232    @Override
233    public void onActivityResume() {
234    }
235
236    @Override
237    public MediaUtil getMediaUtil() {
238        return mMediaUtil;
239    }
240
241    @Override
242    public BugleCarrierConfigValuesLoader getCarrierConfigValuesLoader() {
243        return mCarrierConfigValuesLoader;
244    }
245}
246