1 /*
2  * Copyright (C) 2018 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.car.settings.accounts;
18 
19 import android.accounts.Account;
20 import android.car.drivingstate.CarUxRestrictions;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.SyncAdapterType;
24 import android.os.UserHandle;
25 
26 import androidx.preference.Preference;
27 
28 import com.android.car.settings.R;
29 import com.android.car.settings.common.FragmentController;
30 import com.android.car.settings.common.Logger;
31 import com.android.car.settings.common.PreferenceController;
32 
33 /**
34  * Controller for the account syncing preference.
35  *
36  * <p>Largely derived from {@link com.android.settings.accounts.AccountSyncPreferenceController}.
37  */
38 public class AccountSyncPreferenceController extends PreferenceController<Preference> {
39     private static final Logger LOG = new Logger(AccountSyncPreferenceController.class);
40     private Account mAccount;
41     private UserHandle mUserHandle;
42 
AccountSyncPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)43     public AccountSyncPreferenceController(Context context, String preferenceKey,
44             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
45         super(context, preferenceKey, fragmentController, uxRestrictions);
46     }
47 
48     /** Sets the account that the sync preferences are being shown for. */
setAccount(Account account)49     public void setAccount(Account account) {
50         mAccount = account;
51     }
52 
53     /** Sets the user handle used by the controller. */
setUserHandle(UserHandle userHandle)54     public void setUserHandle(UserHandle userHandle) {
55         mUserHandle = userHandle;
56     }
57 
58     @Override
getPreferenceType()59     protected Class<Preference> getPreferenceType() {
60         return Preference.class;
61     }
62 
63     /**
64      * Verifies that the controller was properly initialized with
65      * {@link #setAccount(Account)} and {@link #setUserHandle(UserHandle)}.
66      *
67      * @throws IllegalStateException if the account is {@code null}
68      */
69     @Override
checkInitialized()70     protected void checkInitialized() {
71         LOG.v("checkInitialized");
72         if (mAccount == null) {
73             throw new IllegalStateException(
74                     "AccountSyncPreferenceController must be initialized by calling "
75                             + "setAccount(Account)");
76         }
77         if (mUserHandle == null) {
78             throw new IllegalStateException(
79                     "AccountSyncPreferenceController must be initialized by calling "
80                             + "setUserHandle(UserHandle)");
81         }
82     }
83 
84     @Override
updateState(Preference preference)85     protected void updateState(Preference preference) {
86         preference.setSummary(getSummary());
87     }
88 
89     @Override
handlePreferenceClicked(Preference preference)90     protected boolean handlePreferenceClicked(Preference preference) {
91         getFragmentController().launchFragment(
92                 AccountSyncDetailsFragment.newInstance(mAccount, mUserHandle));
93         return true;
94     }
95 
getSummary()96     private CharSequence getSummary() {
97         int userId = mUserHandle.getIdentifier();
98         SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(userId);
99         int total = 0;
100         int enabled = 0;
101         if (syncAdapters != null) {
102             for (int i = 0, n = syncAdapters.length; i < n; i++) {
103                 SyncAdapterType sa = syncAdapters[i];
104                 // If the sync adapter isn't for this account type or if the user is not visible,
105                 // don't show it.
106                 if (!sa.accountType.equals(mAccount.type) || !sa.isUserVisible()) {
107                     continue;
108                 }
109                 int syncState =
110                         ContentResolver.getIsSyncableAsUser(mAccount, sa.authority, userId);
111                 if (syncState > 0) {
112                     // If the sync adapter is syncable, add it to the count of items that can be
113                     // synced.
114                     total++;
115 
116                     // If sync is enabled for the sync adapter at the master level or at the account
117                     // level, add it to the count of items that are enabled.
118                     boolean syncEnabled = ContentResolver.getSyncAutomaticallyAsUser(
119                             mAccount, sa.authority, userId);
120                     boolean oneTimeSyncMode =
121                             !ContentResolver.getMasterSyncAutomaticallyAsUser(userId);
122                     if (oneTimeSyncMode || syncEnabled) {
123                         enabled++;
124                     }
125                 }
126             }
127         }
128         if (enabled == 0) {
129             return getContext().getText(R.string.account_sync_summary_all_off);
130         } else if (enabled == total) {
131             return getContext().getText(R.string.account_sync_summary_all_on);
132         } else {
133             return getContext().getString(R.string.account_sync_summary_some_on, enabled, total);
134         }
135     }
136 }
137