1 // Copyright 2013 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.sync.signin; 6 7 import android.accounts.Account; 8 import android.content.Context; 9 import android.os.AsyncTask; 10 import android.preference.PreferenceManager; 11 import android.util.Log; 12 13 import com.google.common.annotations.VisibleForTesting; 14 import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener; 15 16 import org.chromium.base.ObserverList; 17 18 public class ChromeSigninController { 19 public interface Listener { 20 /** 21 * Called when the user signs out of Chrome. 22 */ 23 void onClearSignedInUser(); 24 } 25 26 public static final String TAG = "ChromeSigninController"; 27 28 @VisibleForTesting 29 public static final String SIGNED_IN_ACCOUNT_KEY = "google.services.username"; 30 31 private static final Object LOCK = new Object(); 32 33 private static ChromeSigninController sChromeSigninController; 34 35 private final Context mApplicationContext; 36 37 private final ObserverList<Listener> mListeners = new ObserverList<Listener>(); 38 39 private boolean mGcmInitialized; 40 41 private ChromeSigninController(Context context) { 42 mApplicationContext = context.getApplicationContext(); 43 } 44 45 /** 46 * A factory method for the ChromeSigninController. 47 * 48 * @param context the ApplicationContext is retrieved from the context used as an argument. 49 * @return a singleton instance of the ChromeSigninController 50 */ 51 public static ChromeSigninController get(Context context) { 52 synchronized (LOCK) { 53 if (sChromeSigninController == null) { 54 sChromeSigninController = new ChromeSigninController(context); 55 } 56 } 57 return sChromeSigninController; 58 } 59 60 public Account getSignedInUser() { 61 String syncAccountName = getSignedInAccountName(); 62 if (syncAccountName == null) { 63 return null; 64 } 65 return AccountManagerHelper.createAccountFromName(syncAccountName); 66 } 67 68 public boolean isSignedIn() { 69 return getSignedInAccountName() != null; 70 } 71 72 public void setSignedInAccountName(String accountName) { 73 PreferenceManager.getDefaultSharedPreferences(mApplicationContext).edit() 74 .putString(SIGNED_IN_ACCOUNT_KEY, accountName) 75 .apply(); 76 } 77 78 public void clearSignedInUser() { 79 Log.d(TAG, "Clearing user signed in to Chrome"); 80 setSignedInAccountName(null); 81 82 for (Listener listener : mListeners) { 83 listener.onClearSignedInUser(); 84 } 85 } 86 87 public String getSignedInAccountName() { 88 return PreferenceManager.getDefaultSharedPreferences(mApplicationContext) 89 .getString(SIGNED_IN_ACCOUNT_KEY, null); 90 } 91 92 /** 93 * Adds a Listener. 94 * @param listener Listener to add. 95 */ 96 public void addListener(Listener listener) { 97 mListeners.addObserver(listener); 98 } 99 100 /** 101 * Removes a Listener. 102 * @param listener Listener to remove from the list. 103 */ 104 public void removeListener(Listener listener) { 105 mListeners.removeObserver(listener); 106 } 107 108 /** 109 * Registers for Google Cloud Messaging (GCM) if there is no existing registration. 110 */ 111 public void ensureGcmIsInitialized() { 112 if (mGcmInitialized) return; 113 mGcmInitialized = true; 114 new AsyncTask<Void, Void, Void>() { 115 @Override 116 protected Void doInBackground(Void... arg0) { 117 try { 118 String regId = MultiplexingGcmListener.initializeGcm(mApplicationContext); 119 if (!regId.isEmpty()) 120 Log.d(TAG, "Already registered with GCM"); 121 } catch (IllegalStateException exception) { 122 Log.w(TAG, "Application manifest does not correctly configure GCM; " 123 + "sync notifications will not work", exception); 124 } catch (UnsupportedOperationException exception) { 125 Log.w(TAG, "Device does not support GCM; sync notifications will not work", 126 exception); 127 } 128 return null; 129 } 130 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 131 } 132 } 133