Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(209)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/child_accounts/ChildAccountService.java

Issue 789853002: Add support for child accounts on Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: x Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.child_accounts;
6
7 import android.accounts.Account;
8 import android.accounts.AccountManager;
9 import android.accounts.AccountManagerCallback;
10 import android.accounts.AccountManagerFuture;
11 import android.accounts.AuthenticatorException;
12 import android.accounts.OperationCanceledException;
13 import android.content.Context;
14 import android.os.AsyncTask;
15 import android.util.Log;
16
17 import org.chromium.base.CommandLine;
18 import org.chromium.chrome.ChromeSwitches;
19 import org.chromium.sync.signin.AccountManagerHelper;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Timer;
25 import java.util.TimerTask;
26 import java.util.concurrent.ExecutionException;
27
28 /**
29 * This class detects child accounts and enables special treatment for them.
30 */
31 public class ChildAccountService {
32
33 private static final String TAG = "ChildAccountService";
34
35 /**
36 * An account feature (corresponding to a Gaia service flag) that specifies whether the account
37 * is a child account.
38 */
39 private static final String FEATURE_IS_CHILD_ACCOUNT_KEY = "service_uca";
40
41 /**
42 * The maximum amount of time to wait for the child account check, in millis econds.
43 */
44 private static final int CHILD_ACCOUNT_TIMEOUT_MS = 1000;
45
46 private static final Object sLock = new Object();
47
48 private static ChildAccountService sChildAccountService;
49
50 private final Context mContext;
51
52 // This is null if we haven't determined the child account status yet.
53 private Boolean mHasChildAccount;
54
55 private AccountManagerFuture<Boolean> mAccountManagerFuture;
56
57 private final List<HasChildAccountCallback> mCallbacks = new ArrayList<>();
58
59 private ChildAccountService(Context context) {
60 mContext = context;
61 }
62
63 /**
64 * Returns the shared ChildAccountService instance, creating one if necessar y.
65 * @param context The context to initialize the ChildAccountService with.
66 * @return The shared instance.
67 */
68 public static ChildAccountService getInstance(Context context) {
69 synchronized (sLock) {
70 if (sChildAccountService == null) {
71 sChildAccountService = new ChildAccountService(context.getApplic ationContext());
72 }
73 }
74 return sChildAccountService;
75 }
76
77 /**
78 * A callback to return the result of {@link #checkHasChildAccount}.
79 */
80 public static interface HasChildAccountCallback {
81
82 /**
83 * @param hasChildAccount Whether there is exactly one child account on the device.
84 */
85 public void onChildAccountChecked(boolean hasChildAccount);
86
87 }
88
89 /**
90 * Checks for the presence of child accounts on the device.
91 * @param callback Will be called with the result (see
92 * {@link HasChildAccountCallback#onChildAccountChecked}).
93 */
94 public void checkHasChildAccount(final HasChildAccountCallback callback) {
95 if (mHasChildAccount != null) {
96 callback.onChildAccountChecked(mHasChildAccount);
97 return;
98 }
99
100 Account[] googleAccounts =
101 AccountManagerHelper.get(mContext).getGoogleAccounts();
102 if (googleAccounts.length != 1) {
103 mHasChildAccount = false;
104 callback.onChildAccountChecked(false);
105 if (CommandLine.getInstance().hasSwitch(ChromeSwitches.CHILD_ACCOUNT )) {
106 Log.w(TAG, "Ignoring --" + ChromeSwitches.CHILD_ACCOUNT + " comm and line flag "
107 + "because there are " + googleAccounts.length + " Googl e accounts on the "
108 + "device");
109 }
110 return;
111 }
112 Account account = googleAccounts[0];
113
114 if (shouldForceChildAccount(account)) {
115 mHasChildAccount = true;
116 callback.onChildAccountChecked(true);
117 return;
118 }
119
120 mCallbacks.add(callback);
121
122 if (mAccountManagerFuture != null) return;
123
124 final Timer timer = new Timer();
125
126 String[] features = {FEATURE_IS_CHILD_ACCOUNT_KEY};
127 mAccountManagerFuture = AccountManager.get(mContext).hasFeatures(account , features,
128 new AccountManagerCallback<Boolean>() {
129 @Override
130 public void run(AccountManagerFuture<Boolean> future) {
131 assert future == mAccountManagerFuture;
132 assert future.isDone();
133
134 timer.cancel();
135
136 boolean hasChildAccount = hasChildAccount();
137 for (HasChildAccountCallback callback : mCallbacks) {
138 callback.onChildAccountChecked(hasChildAccount);
139 }
140 }
141 }, null /* handler */);
142
143 timer.schedule(new TimerTask() {
144 @Override
145 public void run() {
146 if (!mAccountManagerFuture.isDone()) mAccountManagerFuture.cance l(true);
147 }}, CHILD_ACCOUNT_TIMEOUT_MS);
148 }
149
150 private boolean shouldForceChildAccount(Account account) {
151 String childAccountName = CommandLine.getInstance().getSwitchValue(
152 ChromeSwitches.CHILD_ACCOUNT);
153 return childAccountName != null && account.name.equals(childAccountName) ;
154 }
155
156 private boolean getFutureResult() {
157 try {
158 return mAccountManagerFuture.getResult();
159 } catch (OperationCanceledException e) {
160 Log.e(TAG, "Timed out fetching child account flag: ", e);
161 } catch (AuthenticatorException e) {
162 Log.e(TAG, "Error while fetching child account flag: ", e);
163 } catch (IOException e) {
164 Log.e(TAG, "Error while fetching child account flag: ", e);
165 }
166 return false;
167 }
168
169 /**
170 * Synchronously checks for the presence of child accounts on the device. Th is method should
171 * only be called after the result has been determined (usually using
172 * {@link #checkHasChildAccount} or {@link #waitUntilFinished} to block).
173 * @return Whether there is a child account on the device.
174 */
175 public boolean hasChildAccount() {
176 // Lazily get the result from the future, so this can be called both fro m the
177 // AccountManagerCallback and after waiting for the future to be resolve d.
178 if (mHasChildAccount == null) {
179 // If the future is not resolved yet, this will assert.
180 mHasChildAccount = getFutureResult();
181 }
182 return mHasChildAccount;
183 }
184
185 /**
186 * Waits until we have determined the child account status. Usually you shou ld use callbacks
187 * instead of this method, see {@link #checkHasChildAccount}.
188 */
189 public void waitUntilFinished() {
190 if (mAccountManagerFuture == null) return;
191 if (mAccountManagerFuture.isDone()) return;
192
193 // This will block in getFutureResult(), but that may only happen on a b ackground thread.
194 try {
195 new AsyncTask<Void, Void, Void>() {
196 @Override
197 protected Void doInBackground(Void... params) {
198 getFutureResult();
199 return null;
200 }
201 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR).get();
202 } catch (ExecutionException e) {
203 Log.w(TAG, "Error while fetching child account flag: ", e);
204 } catch (InterruptedException e) {
205 Log.w(TAG, "Interrupted while fetching child account flag: ", e);
206 }
207 }
208
209 public void onChildAccountSigninComplete() {
210 nativeOnChildAccountSigninComplete();
211 }
212
213 private native void nativeOnChildAccountSigninComplete();
214 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java ('k') | chrome/browser/android/chrome_jni_registrar.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698