1b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik/**
2b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Copyright (C) 2007 The Android Open Source Project
3b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
4b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * use this file except in compliance with the License. You may obtain a copy
6b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * of the License at
7b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
8b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * http://www.apache.org/licenses/LICENSE-2.0
9b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik *
10b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * Unless required by applicable law or agreed to in writing, software
11b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * License for the specific language governing permissions and limitations
14b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * under the License.
15b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik */
16b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
17b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikpackage com.google.android.googlelogin;
18b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
19b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport com.google.android.googleapps.IGoogleLoginService;
20b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
21b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.ComponentName;
22b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.Context;
23b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.content.ServiceConnection;
24b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.os.RemoteException;
25b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.os.IBinder;
26b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport android.os.Looper;
27b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
28b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport java.util.concurrent.locks.Condition;
29b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport java.util.concurrent.locks.Lock;
30b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikimport java.util.concurrent.locks.ReentrantLock;
31b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
32b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik/**
33b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * A helper designed for use by services and background tasks.
34b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * This class provides blocking calls that wrap the binding to the
35b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * {@link IGoogleLoginService GoogleLoginService} and the various
36b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * calls to it.  (Be sure not to call these blocking methods
37b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * from your main thread, though; you always need to create a separate
38b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * worker thread for operations that may block.)
39b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * <p>
40b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * It's best to instantiate this class once
41b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * and make calls on that instance when necessary.
42b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * The helper does not unbind from the GoogleLoginService after
43b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * each call.
44b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * <p>
45b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * When you are done with this object, call close() to unbind from the
46b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik * GoogleLoginService.
47b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik */
48b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erikpublic class GoogleLoginServiceBlockingHelper {
49b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private static final String TAG = "GoogleLoginServiceBlockingHelper";
50b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
51b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private final Context mContext;
52b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private volatile IGoogleLoginService mGoogleLoginService = null;
53b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private Lock mGoogleLoginServiceLock = new ReentrantLock();
54b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private Condition mBindWaitCondition = mGoogleLoginServiceLock.newCondition();
55b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private ServiceConnection mServiceConnection;
56b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
57b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private final int mMinDelaySecs;
58b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private final int mMaxDelaySecs;
59b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private final double mBackoffFactor;
60b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private int mDelay;
61b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
62b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
63b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Whether the Google login service we've bound to is the
64b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Google-provided service. This will be set after we get a callback on the
65b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * service connection, so the value is only valid if
66b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * {@link #mGoogleLoginService} is not null.
67b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * <p>
68b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Locked with the {@link #mGoogleLoginServiceLock} also.
69b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
70b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private boolean mGlsVerified;
71b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
72b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
73b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Initializes the helper.
74b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @param context the Context in which this helper is running
75b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @throws GoogleLoginServiceNotFoundException if the Google login service cannot be found.
76b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
77b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public GoogleLoginServiceBlockingHelper(Context context)
78b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            throws GoogleLoginServiceNotFoundException {
79b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mMinDelaySecs = 5;
80b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mMaxDelaySecs = 5 * 60;   // 5 minutes
81b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mBackoffFactor = 2.0;
82b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mDelay = mMinDelaySecs;
83b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mContext = context;
84b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
85b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        // Ensure the Google Login Service is available
86b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        if (!GoogleAppsVerifier.isServiceAvailable(context,
87b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                GoogleLoginServiceConstants.FULLY_QUALIFIED_SERVICE_NAME)) {
88b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            throw new GoogleLoginServiceNotFoundException(
89b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    GoogleLoginServiceConstants.ERROR_CODE_GLS_NOT_FOUND);
90b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
91b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
92b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mGoogleLoginServiceLock.lock();
93b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
94b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            mServiceConnection = new ServiceConnection() {
95b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                public void onServiceConnected(ComponentName className, IBinder service) {
96b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    try {
97b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        mGoogleLoginServiceLock.lock();
98b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
99b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        /*
100b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                         * Verify that the service we just connected to is
101b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                         * provided by Google. Eventually, this will manifest
102b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                         * into an exception, but we can't throw it here because
103b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                         * our client isn't in the call stack right now.
104b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                         */
105b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        mGlsVerified = GoogleAppsVerifier.isGoogleAppsVerified(mContext);
106b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
107b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        mGoogleLoginService = IGoogleLoginService.Stub.asInterface(service);
108b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
109b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        mBindWaitCondition.signalAll();
110b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    } finally {
111b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        mGoogleLoginServiceLock.unlock();
112b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    }
113b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                }
114b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
115b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                public void onServiceDisconnected(ComponentName className) {
116b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    mGoogleLoginServiceLock.lock();
117b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    mGoogleLoginService = null;
118b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    mGoogleLoginServiceLock.unlock();
119b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                }
120b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            };
121b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
122b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            if (!mContext.bindService(GoogleLoginServiceConstants.SERVICE_INTENT,
123b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                                 mServiceConnection, Context.BIND_AUTO_CREATE)) {
124b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                throw new GoogleLoginServiceNotFoundException(
125b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                        GoogleLoginServiceConstants.ERROR_CODE_GLS_NOT_FOUND);
126b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
127b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } finally {
128b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            mGoogleLoginServiceLock.unlock();
129b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
130b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
131b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
132b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
133b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Releases the binding to the GoogleLoginService (if one exists). This object
134b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * is no longer usable one this method is invoked.
135b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
136b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public void close() {
137b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mGoogleLoginServiceLock.lock();
138b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
139b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            if (mServiceConnection != null) {
140b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                mContext.unbindService(mServiceConnection);
141b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                mServiceConnection = null;
142b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                mGoogleLoginService = null;
143b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
144b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } finally {
145b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            mGoogleLoginServiceLock.unlock();
146b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
147b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
148b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
149b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
150b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Sleep for an exponentially-increasing length of time (bounded
151b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * by mMinDelaySecs and mMaxDelaySecs).
152b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
153b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private void delay() {
154b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
155b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            Thread.sleep(mDelay * 1000L);
156b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } catch (InterruptedException ignore) {
157b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            // just delay for less time
158b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
159b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mDelay *= mBackoffFactor;
160b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        if (mDelay > mMaxDelaySecs) mDelay = mMaxDelaySecs;
161b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
162b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
163b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
164b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Reset the sleep time used by delay() to the minimum.
165b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
166b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private void resetDelay() {
167b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        mDelay = mMinDelaySecs;
168b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
169b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
170b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
171b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Waits for mGoogleLoginService to be nun-null and then returns it. It is set in the
172b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * onServiceConnected that is called as a result of the bind that is called by the
173b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * constructor.
174b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @return the GoogleLoginService, guaranteed to be non-null
175b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @throws GoogleLoginServiceNotFoundException if the Google login service cannot be found.
176b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
177b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private IGoogleLoginService getLoginService() throws GoogleLoginServiceNotFoundException {
178b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        if (Looper.myLooper() == mContext.getMainLooper()) {
179b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            throw new IllegalStateException("calling GoogleLoginServiceBlockingHelper methods "
180b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    + "from your main thread can lead to deadlock");
181b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
182b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
183b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            mGoogleLoginServiceLock.lock();
184b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            while (mGoogleLoginService == null) {
185b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                try {
186b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    mBindWaitCondition.await();
187b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                } catch (InterruptedException e) {
188b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    // keep waiting
189b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                }
190b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
191b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
192b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            checkGoogleLoginServiceVerificationLocked();
193b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
194b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            return mGoogleLoginService;
195b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } finally {
196b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            mGoogleLoginServiceLock.unlock();
197b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
198b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
199b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
200b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    private void checkGoogleLoginServiceVerificationLocked()
201b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            throws GoogleLoginServiceNotFoundException {
202b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        if (mGoogleLoginService != null && !mGlsVerified) {
203b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            throw new GoogleLoginServiceNotFoundException(
204b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                    GoogleLoginServiceConstants.ERROR_CODE_GLS_VERIFICATION_FAILED);
205b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
206b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
207b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
208b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
209b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Gets the login service via getLoginService, which may block, and then
210b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * invokes getAndroidId on it.
211b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     *
212b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @see IGoogleLoginService#getAndroidId()
213b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @return the Android ID for this device (a 64-bit value unique to this
214b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * device); 0 if the device is not registered with google or if the Android
215b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * ID is otherwise unavailable.
216b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @throws GoogleLoginServiceNotFoundException if the Google login service cannot be found.
217b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
218b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public static long getAndroidId(Context context) throws GoogleLoginServiceNotFoundException {
219b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        GoogleLoginServiceBlockingHelper h = new GoogleLoginServiceBlockingHelper(context);
220b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        try {
221b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            return h.getAndroidId();
222b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        } finally {
223b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            h.close();
224b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
225b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
226b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik
227b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    /**
228b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * Gets the login service via getLoginService, which may block, and then
229b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * invokes getAndroidId on it.
230b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     *
231b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @see IGoogleLoginService#getAndroidId()
232b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @return the Android ID for this device (a 64-bit value unique to this
233b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * device); 0 if the device is not registered with google or if the Android
234b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * ID is otherwise unavailable.
235b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     * @throws GoogleLoginServiceNotFoundException if the Google login service cannot be found.
236b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik     */
237b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    public long getAndroidId() throws GoogleLoginServiceNotFoundException {
238b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        resetDelay();
239b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        while (true) {
240b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            IGoogleLoginService loginService = getLoginService();
241b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            try {
242b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                return loginService.getAndroidId();
243b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            } catch (RemoteException e) {
244b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                // the next call to getLoginService will wait until the service
245b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                // is reconnected
246b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik                delay();
247b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik            }
248b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik        }
249b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik    }
250b0143ecb5bfc6eeb272b2ec790b40d252c32e6a1Erik}
251