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

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: sync 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 sChildAccountManager;
Marc Treib 2014/12/10 11:53:27 nit: rename to sChildAccountService
Bernhard Bauer 2014/12/11 09:07:58 Done.
49
50 private final Context mContext;
51
52 // "Boolean" rather than "boolean" to force a crash if hasChildAccount is ca lled too soon
Marc Treib 2014/12/10 11:53:27 So essentially a three-way bool? http://thedailywt
Bernhard Bauer 2014/12/11 09:07:58 Well, it would be an optional boolean, if Java had
Marc Treib 2014/12/11 12:21:31 I'd still argue that the "optional" part is what y
Bernhard Bauer 2014/12/11 13:38:59 Updated the comment.
53 // (i.e. without calling waitUntilFinished() or checkHasChildAccount()).
54 private Boolean mHasChildAccount;
55
56 private AccountManagerFuture<Boolean> mAccountManagerFuture;
57
58 private final List<HasChildAccountCallback> mCallbacks = new ArrayList<>();
59
60 private ChildAccountService(Context context) {
61 mContext = context;
62 }
63
64 /**
65 * Returns the shared ChildAccountManager instance, creating one if necessar y.
Marc Treib 2014/12/10 11:53:27 ChildAccountService
Bernhard Bauer 2014/12/11 09:07:58 Done.
66 * @param context The context to initialize the ChildAccountManager with.
67 * @return The shared instance.
68 */
69 public static ChildAccountService getInstance(Context context) {
70 synchronized (sLock) {
71 if (sChildAccountManager == null) {
72 sChildAccountManager = new ChildAccountService(context.getApplic ationContext());
73 }
74 }
75 return sChildAccountManager;
76 }
77
78 /**
79 * A callback to return the result of {@link #checkHasChildAccount}.
80 */
81 public static interface HasChildAccountCallback {
82
83 /**
84 * @param hasChildAccount Whether there is exactly one child account on the device.
85 */
86 public void onChildAccountChecked(boolean hasChildAccount);
87
88 }
89
90 /**
91 * Checks for the presence of child accounts on the device.
92 * @param callback Will be called with the result (see
93 * {@link HasChildAccountCallback#onChildAccountChecked}).
94 */
95 public void checkHasChildAccount(final HasChildAccountCallback callback) {
96 if (mHasChildAccount != null) {
97 callback.onChildAccountChecked(mHasChildAccount);
98 return;
99 }
100
101 Account[] googleAccounts =
102 AccountManagerHelper.get(mContext).getGoogleAccounts();
103 if (googleAccounts.length != 1) {
Marc Treib 2014/12/10 11:53:27 Could this condition potentially change between ca
Bernhard Bauer 2014/12/11 09:07:58 Once full Unicorn support is in GMSCore etc., GMSC
Marc Treib 2014/12/11 12:21:31 Acknowledged.
104 mHasChildAccount = false;
105 callback.onChildAccountChecked(false);
106 return;
107 }
108 Account account = googleAccounts[0];
109
110 if (forceChildAccount(account)) {
Marc Treib 2014/12/10 11:53:27 Should the debug flag work even if there's more th
Bernhard Bauer 2014/12/11 09:07:58 Like I mentioned above, right now I don't really c
Marc Treib 2014/12/11 12:21:31 This is just a debug flag anyway, right? I was jus
Bernhard Bauer 2014/12/11 13:38:59 Hm. There is some other code in Clank that relies
Marc Treib 2014/12/11 15:04:31 Acknowledged. It's not worth spending extra effort
Bernhard Bauer 2014/12/11 15:44:18 Good idea! Done.
111 mHasChildAccount = true;
112 callback.onChildAccountChecked(true);
113 return;
114 }
115
116 mCallbacks.add(callback);
117
118 if (mAccountManagerFuture != null) return;
119
120 final Timer timer = new Timer();
121
122 String[] features = {FEATURE_IS_CHILD_ACCOUNT_KEY};
123 mAccountManagerFuture = AccountManager.get(mContext).hasFeatures(account , features,
124 new AccountManagerCallback<Boolean>() {
125 @Override
126 public void run(AccountManagerFuture<Boolean> future) {
127 assert future == mAccountManagerFuture;
128 assert future.isDone();
129
130 timer.cancel();
131
132 boolean hasChildAccount = hasChildAccount();
Marc Treib 2014/12/10 11:53:27 Should you set mHasChildAccount here?
Bernhard Bauer 2014/12/11 09:07:58 hasChildAccount() will do that.
Marc Treib 2014/12/11 12:21:31 Well, if you do it here (and in waitUntilFinished)
Bernhard Bauer 2014/12/11 13:38:59 The problem here is that this callback will be pos
Marc Treib 2014/12/11 15:04:31 I'm not worried about setting it at the earliest p
133 for (HasChildAccountCallback callback : mCallbacks) {
134 callback.onChildAccountChecked(hasChildAccount);
135 }
136 }
137 }, null /* handler */);
138
139 timer.schedule(new TimerTask() {
140 @Override
141 public void run() {
142 if (!mAccountManagerFuture.isDone()) mAccountManagerFuture.cance l(true);
143 }}, CHILD_ACCOUNT_TIMEOUT_MS);
144 }
145
146 private boolean forceChildAccount(Account account) {
Marc Treib 2014/12/10 11:53:27 Rename to shouldForceChildAccount?
Bernhard Bauer 2014/12/11 09:07:58 Done.
147 String childAccountName = CommandLine.getInstance().getSwitchValue(
148 ChromeSwitches.CHILD_ACCOUNT);
Marc Treib 2014/12/10 11:53:27 nit: Indentation?
Bernhard Bauer 2014/12/11 09:07:58 8 space indent for continued lines is actually cor
Marc Treib 2014/12/11 12:21:31 Acknowledged.
149 return childAccountName != null && account.name.equals(childAccountName) ;
150 }
151
152 private boolean getFutureResult() {
153 try {
154 return mAccountManagerFuture.getResult();
155 } catch (OperationCanceledException e) {
156 Log.e(TAG, "Timed out fetching child account flag: ", e);
157 } catch (AuthenticatorException e) {
158 Log.e(TAG, "Error while fetching child account flag: ", e);
159 } catch (IOException e) {
160 Log.e(TAG, "Error while fetching child account flag: ", e);
161 }
162 return false;
163 }
164
165 /**
166 * Synchronously checks for the presence of child accounts on the device. Th is method should
167 * only be called after the result has been determined (usually using
168 * {@link #checkHasChildAccount} or {@link #waitUntilFinished} to block).
169 * @return Whether there is a child account on the device.
170 */
171 public boolean hasChildAccount() {
172 // Lazily get the result from the future, so this can be called both fro m the
173 // AccountManagerCallback and after waiting for the future to be resolve d.
174 if (mHasChildAccount == null) {
175 mHasChildAccount = getFutureResult();
Marc Treib 2014/12/10 11:53:27 So this will block on the result, but only if chec
Bernhard Bauer 2014/12/11 09:07:58 Correct! :) The idea here is that you call checkHa
Marc Treib 2014/12/11 12:21:31 Hm. I guess I'd prefer to fire off the check here
Bernhard Bauer 2014/12/11 13:38:59 Yeah, the reason I don't do that is because if som
Marc Treib 2014/12/11 15:04:31 Acknowledged.
176 }
177 return mHasChildAccount;
178 }
179
180 /**
181 * Waits until we have determined the child account status. Usually you shou ld use callbacks
182 * instead of this method, see {@link #checkHasChildAccount}.
183 */
184 public void waitUntilFinished() {
Marc Treib 2014/12/10 11:53:27 What does this method do, since it doesn't actuall
Bernhard Bauer 2014/12/11 09:07:58 getFutureResult() will block. I updated the commen
Marc Treib 2014/12/11 12:21:31 Ah, I missed the ".get()" at the end. So blocking
Bernhard Bauer 2014/12/11 13:38:59 Welcome to Android :) I do feel somewhat bad for
Marc Treib 2014/12/11 15:04:31 Acknowledged.
185 if (mAccountManagerFuture == null) return;
186 if (mAccountManagerFuture.isDone()) return;
187
188 // Waiting on the account manager future is only allowed on a background thread.
189 try {
190 new AsyncTask<Void, Void, Void>() {
191 @Override
192 protected Void doInBackground(Void... params) {
193 getFutureResult();
194 return null;
195 }
196 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR).get();
197 } catch (ExecutionException e) {
198 Log.w(TAG, "Error while fetching child account flag: ", e);
199 } catch (InterruptedException e) {
200 Log.w(TAG, "Interrupted while fetching child account flag: ", e);
201 }
202 }
203
204 public void onChildAccountSigninComplete() {
205 nativeOnChildAccountSigninComplete();
206 }
207
208 private native void nativeOnChildAccountSigninComplete();
209 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698