Skip to content

Commit 7841f9a

Browse files
committed
Merge branch '5.03_Registering_with_GCM' into 5.04_Receiving_a_Message
2 parents 2ed375e + b6d88a8 commit 7841f9a

6 files changed

Lines changed: 169 additions & 167 deletions

File tree

app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
apply plugin: 'com.android.application'
2+
apply plugin: 'com.google.gms.google-services'
23

34
android {
45
compileSdkVersion 21
@@ -24,5 +25,5 @@ dependencies {
2425
compile 'com.github.bumptech.glide:glide:3.5.2'
2526
compile 'com.android.support:appcompat-v7:21.0.2'
2627
compile 'com.android.support:support-annotations:22.0.0'
27-
compile 'com.google.android.gms:play-services-gcm:7.0.0'
28+
compile 'com.google.android.gms:play-services-gcm:7.5.0'
2829
}

app/src/main/AndroidManifest.xml

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
android:name="android.permission.ACCESS_NETWORK_STATE" />
3434

3535
<!-- Permissions required for Google Cloud Messaging -->
36+
<uses-permission android:name="android.permission.WAKE_LOCK" />
3637
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
3738
<permission android:name="com.example.android.sunshine.app.permission.C2D_MESSAGE"
3839
android:protectionLevel="signature" />
@@ -100,15 +101,35 @@
100101
android:resource="@xml/syncadapter" />
101102
</service>
102103

103-
<!-- GCM receiver - Commented out until we write the class -->
104-
<!--<receiver-->
105-
<!--android:name=".GcmBroadcastReceiver"-->
106-
<!--android:permission="com.google.android.c2dm.permission.SEND" >-->
107-
<!--<intent-filter>-->
108-
<!--<action android:name="com.google.android.c2dm.intent.RECEIVE" />-->
109-
<!--<category android:name="com.example.android.sunshine.app" />-->
110-
<!--</intent-filter>-->
111-
<!--</receiver>-->
104+
<!-- The Google Cloud Messaging receiver and services -->
105+
<receiver
106+
android:name="com.google.android.gms.gcm.GcmReceiver"
107+
android:exported="true"
108+
android:permission="com.google.android.c2dm.permission.SEND" >
109+
<intent-filter>
110+
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
111+
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
112+
<category android:name="com.example.android.sunshine.app" />
113+
</intent-filter>
114+
</receiver>
115+
<service
116+
android:name="gcm.MyGcmListenerService"
117+
android:exported="false" >
118+
<intent-filter>
119+
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
120+
</intent-filter>
121+
</service>
122+
<service
123+
android:name="gcm.MyInstanceIDListenerService"
124+
android:exported="false">
125+
<intent-filter>
126+
<action android:name="com.google.android.gms.iid.InstanceID"/>
127+
</intent-filter>
128+
</service>
129+
<service
130+
android:name=".gcm.RegistrationIntentService"
131+
android:exported="false" >
132+
</service>
112133
</application>
113134

114135
</manifest>

app/src/main/java/com/example/android/sunshine/app/MainActivity.java

Lines changed: 24 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,30 @@
1515
*/
1616
package com.example.android.sunshine.app;
1717

18-
import android.app.AlertDialog;
19-
import android.content.Context;
2018
import android.content.Intent;
2119
import android.content.SharedPreferences;
22-
import android.content.pm.PackageInfo;
23-
import android.content.pm.PackageManager;
2420
import android.net.Uri;
25-
import android.os.AsyncTask;
2621
import android.os.Bundle;
22+
import android.preference.PreferenceManager;
2723
import android.support.v7.app.ActionBarActivity;
2824
import android.util.Log;
2925
import android.view.Menu;
3026
import android.view.MenuItem;
3127

28+
import com.example.android.sunshine.app.gcm.RegistrationIntentService;
3229
import com.example.android.sunshine.app.sync.SunshineSyncAdapter;
3330
import com.google.android.gms.common.ConnectionResult;
34-
import com.google.android.gms.common.GooglePlayServicesUtil;
35-
import com.google.android.gms.gcm.GoogleCloudMessaging;
36-
37-
import java.io.IOException;
38-
import java.util.concurrent.atomic.AtomicInteger;
31+
import com.google.android.gms.common.GoogleApiAvailability;
3932

4033
public class MainActivity extends ActionBarActivity implements ForecastFragment.Callback {
4134

4235
private final String LOG_TAG = MainActivity.class.getSimpleName();
4336
private static final String DETAILFRAGMENT_TAG = "DFTAG";
4437
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
45-
public static final String PROPERTY_REG_ID = "registration_id";
46-
private static final String PROPERTY_APP_VERSION = "appVersion";
47-
48-
/**
49-
* Substitute you own sender ID here. This is the project number you got
50-
* from the API Console.
51-
*/
52-
String SENDER_ID = "Your-Sender-ID";
38+
public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
5339

5440
private boolean mTwoPane;
5541
private String mLocation;
56-
private GoogleCloudMessaging mGcm;
5742

5843
@Override
5944
protected void onCreate(Bundle savedInstanceState) {
@@ -85,25 +70,21 @@ protected void onCreate(Bundle savedInstanceState) {
8570

8671
SunshineSyncAdapter.initializeSyncAdapter(this);
8772

88-
// If Google Play Services is not available, some features, such as GCM-powered weather
89-
// alerts, will not be available.
73+
// If Google Play Services is up to date, we'll want to register GCM. If it is not, we'll
74+
// skip the registration and this device will not receive any downstream messages from
75+
// our fake server. Because weather alerts are not a core feature of the app, this should
76+
// not affect the behavior of the app, from a user perspective.
9077
if (checkPlayServices()) {
91-
mGcm = GoogleCloudMessaging.getInstance(this);
92-
String regId = getRegistrationId(this);
93-
94-
if (SENDER_ID.equals("Your-Sender-ID")) {
95-
new AlertDialog.Builder(this)
96-
.setTitle("Needs Sender ID")
97-
.setMessage("GCM will not function in Sunshine until you replace your Sender ID with a Sender ID from the Google Developers Console.")
98-
.setPositiveButton(android.R.string.ok, null)
99-
.create().show();
100-
} else if (regId.isEmpty()) {
101-
registerInBackground(this);
78+
// Because this is the initial creation of the app, we'll want to be certain we have
79+
// a token. If we do not, then we will start the IntentService that will register this
80+
// application with GCM.
81+
SharedPreferences sharedPreferences =
82+
PreferenceManager.getDefaultSharedPreferences(this);
83+
boolean sentToken = sharedPreferences.getBoolean(SENT_TOKEN_TO_SERVER, false);
84+
if (!sentToken) {
85+
Intent intent = new Intent(this, RegistrationIntentService.class);
86+
startService(intent);
10287
}
103-
} else {
104-
Log.i(LOG_TAG, "No valid Google Play Services APK. Weather alerts will be disabled.");
105-
// Store regID as null
106-
storeRegistrationId(this, null);
10788
}
10889
}
10990

@@ -126,22 +107,16 @@ public boolean onOptionsItemSelected(MenuItem item) {
126107
startActivity(new Intent(this, SettingsActivity.class));
127108
return true;
128109
}
110+
129111
return super.onOptionsItemSelected(item);
130112
}
131113

132114
@Override
133115
protected void onResume() {
134116
super.onResume();
135-
136-
// If Google Play Services is not available, some features, such as GCM-powered weather
137-
// alerts, will not be available.
138-
if (!checkPlayServices()) {
139-
// Store regID as null
140-
}
141-
142-
String location = Utility.getPreferredLocation(this);
117+
String location = Utility.getPreferredLocation( this );
143118
// update the location in our second pane using the fragment manager
144-
if (location != null && !location.equals(mLocation)) {
119+
if (location != null && !location.equals(mLocation)) {
145120
ForecastFragment ff = (ForecastFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_forecast);
146121
if ( null != ff ) {
147122
ff.onLocationChanged();
@@ -182,10 +157,11 @@ public void onItemSelected(Uri contentUri) {
182157
* the Google Play Store or enable it in the device's system settings.
183158
*/
184159
private boolean checkPlayServices() {
185-
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
160+
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
161+
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
186162
if (resultCode != ConnectionResult.SUCCESS) {
187-
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
188-
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
163+
if (apiAvailability.isUserResolvableError(resultCode)) {
164+
apiAvailability.getErrorDialog(this, resultCode,
189165
PLAY_SERVICES_RESOLUTION_REQUEST).show();
190166
} else {
191167
Log.i(LOG_TAG, "This device is not supported.");
@@ -195,113 +171,4 @@ private boolean checkPlayServices() {
195171
}
196172
return true;
197173
}
198-
199-
/**
200-
* Gets the current registration ID for application on GCM service.
201-
* <p>
202-
* If result is empty, the app needs to register.
203-
*
204-
* @return registration ID, or empty string if there is no existing
205-
* registration ID.
206-
*/
207-
private String getRegistrationId(Context context) {
208-
final SharedPreferences prefs = getGCMPreferences(context);
209-
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
210-
if (registrationId.isEmpty()) {
211-
Log.i(LOG_TAG, "GCM Registration not found.");
212-
return "";
213-
}
214-
215-
// Check if app was updated; if so, it must clear the registration ID
216-
// since the existing registration ID is not guaranteed to work with
217-
// the new app version.
218-
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
219-
int currentVersion = getAppVersion(context);
220-
if (registeredVersion != currentVersion) {
221-
Log.i(LOG_TAG, "App version changed.");
222-
return "";
223-
}
224-
return registrationId;
225-
}
226-
227-
/**
228-
* @return Application's {@code SharedPreferences}.
229-
*/
230-
private SharedPreferences getGCMPreferences(Context context) {
231-
// Sunshine persists the registration ID in shared preferences, but
232-
// how you store the registration ID in your app is up to you. Just make sure
233-
// that it is private!
234-
return getSharedPreferences(MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
235-
}
236-
237-
/**
238-
* @return Application's version code from the {@code PackageManager}.
239-
*/
240-
private static int getAppVersion(Context context) {
241-
try {
242-
PackageInfo packageInfo = context.getPackageManager()
243-
.getPackageInfo(context.getPackageName(), 0);
244-
return packageInfo.versionCode;
245-
} catch (PackageManager.NameNotFoundException e) {
246-
// Should never happen. WHAT DID YOU DO?!?!
247-
throw new RuntimeException("Could not get package name: " + e);
248-
}
249-
}
250-
251-
/**
252-
* Registers the application with GCM servers asynchronously.
253-
* <p>
254-
* Stores the registration ID and app versionCode in the application's
255-
* shared preferences.
256-
*/
257-
private void registerInBackground(final Context context) {
258-
new AsyncTask<Void, Void, Void>() {
259-
@Override
260-
protected Void doInBackground(Void... params) {
261-
String msg = "";
262-
try {
263-
if (mGcm == null) {
264-
mGcm = GoogleCloudMessaging.getInstance(context);
265-
}
266-
String regId = mGcm.register(SENDER_ID);
267-
msg = "Device registered, registration ID=" + regId;
268-
269-
// You should send the registration ID to your server over HTTP,
270-
// so it can use GCM/HTTP or CCS to send messages to your app.
271-
// The request to your server should be authenticated if your app
272-
// is using accounts.
273-
//sendRegistrationIdToBackend();
274-
// For this demo: we don't need to send it because the device
275-
// will send upstream messages to a server that echo back the
276-
// message using the 'from' address in the message.
277-
278-
// Persist the registration ID - no need to register again.
279-
storeRegistrationId(context, regId);
280-
} catch (IOException ex) {
281-
msg = "Error :" + ex.getMessage();
282-
// TODO: If there is an error, don't just keep trying to register.
283-
// Require the user to click a button again, or perform
284-
// exponential back-off.
285-
}
286-
return null;
287-
}
288-
}.execute(null, null, null);
289-
}
290-
291-
/**
292-
* Stores the registration ID and app versionCode in the application's
293-
* {@code SharedPreferences}.
294-
*
295-
* @param context application's context.
296-
* @param regId registration ID
297-
*/
298-
private void storeRegistrationId(Context context, String regId) {
299-
final SharedPreferences prefs = getGCMPreferences(context);
300-
int appVersion = getAppVersion(context);
301-
Log.i(LOG_TAG, "Saving regId on app version " + appVersion);
302-
SharedPreferences.Editor editor = prefs.edit();
303-
editor.putString(PROPERTY_REG_ID, regId);
304-
editor.putInt(PROPERTY_APP_VERSION, appVersion);
305-
editor.commit();
306-
}
307174
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (C) 2015 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.android.sunshine.app.gcm;
18+
19+
import android.content.Intent;
20+
import com.google.android.gms.iid.InstanceIDListenerService;
21+
22+
public class MyInstanceIDListenerService extends InstanceIDListenerService {
23+
private static final String TAG = "MyInstanceIDLS";
24+
25+
/**
26+
* Called if InstanceID token is updated. This may occur if the security of
27+
* the previous token had been compromised. This call is initiated by the
28+
* InstanceID provider.
29+
*/
30+
@Override
31+
public void onTokenRefresh() {
32+
// Fetch updated Instance ID token.
33+
Intent intent = new Intent(this, RegistrationIntentService.class);
34+
startService(intent);
35+
}
36+
}

0 commit comments

Comments
 (0)