12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)package org.chromium.sync.signin;
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.Account;
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Context;
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.AsyncTask;
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.preference.PreferenceManager;
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.util.Log;
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting;
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import org.chromium.base.CommandLine;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.ObserverList;
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import org.chromium.sync.SyncSwitches;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public class ChromeSigninController {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public interface Listener {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * Called when the user signs out of Chrome.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         */
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        void onClearSignedInUser();
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    public static final String TAG = "ChromeSigninController";
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @VisibleForTesting
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String SIGNED_IN_ACCOUNT_KEY = "google.services.username";
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final Object LOCK = new Object();
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static ChromeSigninController sChromeSigninController;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final Context mApplicationContext;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final ObserverList<Listener> mListeners = new ObserverList<Listener>();
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mGcmInitialized;
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private ChromeSigninController(Context context) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mApplicationContext = context.getApplicationContext();
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * A factory method for the ChromeSigninController.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param context the ApplicationContext is retrieved from the context used as an argument.
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return a singleton instance of the ChromeSigninController
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static ChromeSigninController get(Context context) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (LOCK) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sChromeSigninController == null) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sChromeSigninController = new ChromeSigninController(context);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return sChromeSigninController;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public Account getSignedInUser() {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        String syncAccountName = getSignedInAccountName();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (syncAccountName == null) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return null;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return AccountManagerHelper.createAccountFromName(syncAccountName);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public boolean isSignedIn() {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return getSignedInAccountName() != null;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void setSignedInAccountName(String accountName) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        PreferenceManager.getDefaultSharedPreferences(mApplicationContext).edit()
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                .putString(SIGNED_IN_ACCOUNT_KEY, accountName)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                .apply();
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void clearSignedInUser() {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Log.d(TAG, "Clearing user signed in to Chrome");
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        setSignedInAccountName(null);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (Listener listener : mListeners) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            listener.onClearSignedInUser();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public String getSignedInAccountName() {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return PreferenceManager.getDefaultSharedPreferences(mApplicationContext)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                .getString(SIGNED_IN_ACCOUNT_KEY, null);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Adds a Listener.
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param listener Listener to add.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void addListener(Listener listener) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mListeners.addObserver(listener);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Removes a Listener.
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param listener Listener to remove from the list.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void removeListener(Listener listener) {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mListeners.removeObserver(listener);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Registers for Google Cloud Messaging (GCM) if there is no existing registration.
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void ensureGcmIsInitialized() {
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (mGcmInitialized) return;
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mGcmInitialized = true;
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new AsyncTask<Void, Void, Void>() {
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            protected Void doInBackground(Void... arg0) {
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                if (CommandLine.getInstance().hasSwitch(
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                        SyncSwitches.DISABLE_SYNC_GCM_IN_ORDER_TO_TRY_PUSH_API)) {
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    Log.w(TAG, "Sync GCM notifications disabled in order to try Push API!");
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    return null;
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                }
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                try {
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    String regId = MultiplexingGcmListener.initializeGcm(mApplicationContext);
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    if (!regId.isEmpty())
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        Log.d(TAG, "Already registered with GCM");
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                } catch (IllegalStateException exception) {
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    Log.w(TAG, "Application manifest does not correctly configure GCM; "
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            + "sync notifications will not work", exception);
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                } catch (UnsupportedOperationException exception) {
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    Log.w(TAG, "Device does not support GCM; sync notifications will not work",
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            exception);
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                }
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                return null;
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
140