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.content.ContentResolver; 21 import android.content.Context; 22 import android.content.SyncAdapterType; 23 import android.content.SyncStatusObserver; 24 import android.os.Bundle; 25 import android.os.UserHandle; 26 27 import androidx.annotation.XmlRes; 28 29 import com.android.car.settings.R; 30 import com.android.car.settings.common.SettingsFragment; 31 import com.android.car.ui.toolbar.MenuItem; 32 import com.android.settingslib.utils.ThreadUtils; 33 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Set; 37 38 /** 39 * Shows details for syncing an account. 40 */ 41 public class AccountSyncDetailsFragment extends SettingsFragment { 42 private static final String EXTRA_ACCOUNT = "extra_account"; 43 private static final String EXTRA_USER_HANDLE = "extra_user_handle"; 44 private boolean mIsStarted = false; 45 private Object mStatusChangeListenerHandle; 46 private MenuItem mSyncButton; 47 private SyncStatusObserver mSyncStatusObserver = 48 which -> ThreadUtils.postOnMainThread(() -> { 49 // The observer call may occur even if the fragment hasn't been started, so 50 // only force an update if the fragment hasn't been stopped. 51 if (mIsStarted) { 52 updateSyncButton(); 53 } 54 }); 55 56 /** 57 * Creates a new AccountSyncDetailsFragment. 58 * 59 * <p>Passes the provided account and user handle to the fragment via fragment arguments. 60 */ newInstance(Account account, UserHandle userHandle)61 public static AccountSyncDetailsFragment newInstance(Account account, UserHandle userHandle) { 62 AccountSyncDetailsFragment accountSyncDetailsFragment = new AccountSyncDetailsFragment(); 63 Bundle bundle = new Bundle(); 64 bundle.putParcelable(EXTRA_ACCOUNT, account); 65 bundle.putParcelable(EXTRA_USER_HANDLE, userHandle); 66 accountSyncDetailsFragment.setArguments(bundle); 67 return accountSyncDetailsFragment; 68 } 69 70 @Override 71 @XmlRes getPreferenceScreenResId()72 protected int getPreferenceScreenResId() { 73 return R.xml.account_sync_details_fragment; 74 } 75 76 @Override getToolbarMenuItems()77 public List<MenuItem> getToolbarMenuItems() { 78 return Collections.singletonList(mSyncButton); 79 } 80 81 @Override onCreate(Bundle savedInstanceState)82 public void onCreate(Bundle savedInstanceState) { 83 super.onCreate(savedInstanceState); 84 85 mSyncButton = new MenuItem.Builder(getContext()).build(); 86 updateSyncButton(); 87 } 88 89 @Override onAttach(Context context)90 public void onAttach(Context context) { 91 super.onAttach(context); 92 93 Account account = getArguments().getParcelable(EXTRA_ACCOUNT); 94 UserHandle userHandle = getArguments().getParcelable(EXTRA_USER_HANDLE); 95 96 use(AccountDetailsWithSyncStatusPreferenceController.class, 97 R.string.pk_account_details_with_sync) 98 .setAccount(account); 99 use(AccountDetailsWithSyncStatusPreferenceController.class, 100 R.string.pk_account_details_with_sync) 101 .setUserHandle(userHandle); 102 103 use(AccountSyncDetailsPreferenceController.class, R.string.pk_account_sync_details) 104 .setAccount(account); 105 use(AccountSyncDetailsPreferenceController.class, R.string.pk_account_sync_details) 106 .setUserHandle(userHandle); 107 } 108 109 @Override onActivityCreated(Bundle savedInstanceState)110 public void onActivityCreated(Bundle savedInstanceState) { 111 super.onActivityCreated(savedInstanceState); 112 updateSyncButton(); 113 } 114 115 @Override onStart()116 public void onStart() { 117 super.onStart(); 118 mIsStarted = true; 119 mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener( 120 ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE 121 | ContentResolver.SYNC_OBSERVER_TYPE_STATUS 122 | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, mSyncStatusObserver); 123 } 124 125 @Override onStop()126 public void onStop() { 127 super.onStop(); 128 mIsStarted = false; 129 if (mStatusChangeListenerHandle != null) { 130 ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle); 131 } 132 } 133 updateSyncButton()134 private void updateSyncButton() { 135 // Set the button to either request or cancel sync, depending on the current state 136 UserHandle userHandle = getArguments().getParcelable(EXTRA_USER_HANDLE); 137 boolean hasActiveSyncs = !ContentResolver.getCurrentSyncsAsUser( 138 userHandle.getIdentifier()).isEmpty(); 139 140 // If there are active syncs, clicking the button with cancel them. Otherwise, clicking the 141 // button will start them. 142 mSyncButton.setTitle( 143 hasActiveSyncs ? R.string.sync_button_sync_cancel : R.string.sync_button_sync_now); 144 mSyncButton.setOnClickListener(hasActiveSyncs 145 ? i -> cancelSyncForEnabledProviders() 146 : i -> requestSyncForEnabledProviders()); 147 } 148 requestSyncForEnabledProviders()149 private void requestSyncForEnabledProviders() { 150 Account account = getArguments().getParcelable(EXTRA_ACCOUNT); 151 UserHandle userHandle = getArguments().getParcelable(EXTRA_USER_HANDLE); 152 int userId = userHandle.getIdentifier(); 153 154 Set<SyncAdapterType> adapters = AccountSyncHelper.getSyncableSyncAdaptersForAccount(account, 155 userHandle); 156 for (SyncAdapterType adapter : adapters) { 157 AccountSyncHelper.requestSyncIfAllowed(account, adapter.authority, userId); 158 } 159 } 160 cancelSyncForEnabledProviders()161 private void cancelSyncForEnabledProviders() { 162 Account account = getArguments().getParcelable(EXTRA_ACCOUNT); 163 UserHandle userHandle = getArguments().getParcelable(EXTRA_USER_HANDLE); 164 int userId = userHandle.getIdentifier(); 165 166 Set<SyncAdapterType> adapters = AccountSyncHelper.getSyncableSyncAdaptersForAccount(account, 167 userHandle); 168 for (SyncAdapterType adapter : adapters) { 169 ContentResolver.cancelSyncAsUser(account, adapter.authority, userId); 170 } 171 } 172 } 173