From f8ee5faf3d2dee2e8db2c84f864baeeb8eb7b4e8 Mon Sep 17 00:00:00 2001 From: saltfactory Date: Tue, 9 Jun 2015 17:27:09 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Android=20GCM=20=EC=98=88=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 + bash/gcm_sender.sh | 6 + node/gcm_provider.js | 26 +++ node/package.json | 8 + sf-gcm-demo/.gitignore | 7 + sf-gcm-demo/app/.gitignore | 1 + sf-gcm-demo/app/build.gradle | 28 +++ sf-gcm-demo/app/proguard-rules.pro | 17 ++ .../saltfactory/demo/gcm/ApplicationTest.java | 13 ++ sf-gcm-demo/app/src/main/AndroidManifest.xml | 64 +++++++ .../saltfactory/demo/gcm/MainActivity.java | 144 +++++++++++++++ .../demo/gcm/MyGcmListenerService.java | 66 +++++++ .../demo/gcm/MyInstanceIDListenerService.java | 19 ++ .../demo/gcm/QuickstartPreferences.java | 12 ++ .../demo/gcm/RegistrationIntentService.java | 61 +++++++ .../ic_stat_ic_notification.png | Bin 0 -> 659 bytes .../drawable-hdpi/ic_stat_ic_notification.png | Bin 0 -> 764 bytes .../ic_stat_ic_notification.png | Bin 0 -> 494 bytes .../drawable-mdpi/ic_stat_ic_notification.png | Bin 0 -> 499 bytes .../ic_stat_ic_notification.png | Bin 0 -> 979 bytes .../ic_stat_ic_notification.png | Bin 0 -> 1058 bytes .../ic_stat_ic_notification.png | Bin 0 -> 1768 bytes .../ic_stat_ic_notification.png | Bin 0 -> 1763 bytes .../app/src/main/res/layout/activity_main.xml | 24 +++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3393 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2086 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4244 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6900 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9783 bytes .../app/src/main/res/values-v21/styles.xml | 8 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../app/src/main/res/values/colors.xml | 8 + .../app/src/main/res/values/dimens.xml | 5 + .../app/src/main/res/values/strings.xml | 6 + .../app/src/main/res/values/styles.xml | 10 ++ sf-gcm-demo/build.gradle | 20 +++ sf-gcm-demo/gradle.properties | 18 ++ sf-gcm-demo/gradlew | 164 ++++++++++++++++++ sf-gcm-demo/gradlew.bat | 90 ++++++++++ sf-gcm-demo/settings.gradle | 1 + 40 files changed, 840 insertions(+) create mode 100644 bash/gcm_sender.sh create mode 100644 node/gcm_provider.js create mode 100644 node/package.json create mode 100644 sf-gcm-demo/.gitignore create mode 100644 sf-gcm-demo/app/.gitignore create mode 100644 sf-gcm-demo/app/build.gradle create mode 100644 sf-gcm-demo/app/proguard-rules.pro create mode 100644 sf-gcm-demo/app/src/androidTest/java/net/saltfactory/demo/gcm/ApplicationTest.java create mode 100644 sf-gcm-demo/app/src/main/AndroidManifest.xml create mode 100644 sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MainActivity.java create mode 100644 sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyGcmListenerService.java create mode 100644 sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyInstanceIDListenerService.java create mode 100644 sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/QuickstartPreferences.java create mode 100644 sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/RegistrationIntentService.java create mode 100644 sf-gcm-demo/app/src/main/res/drawable-hdpi-v11/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-hdpi/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-mdpi-v11/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-mdpi/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-xhdpi-v11/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-xhdpi/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-xxhdpi-v11/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/drawable-xxhdpi/ic_stat_ic_notification.png create mode 100644 sf-gcm-demo/app/src/main/res/layout/activity_main.xml create mode 100644 sf-gcm-demo/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 sf-gcm-demo/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 sf-gcm-demo/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 sf-gcm-demo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 sf-gcm-demo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 sf-gcm-demo/app/src/main/res/values-v21/styles.xml create mode 100644 sf-gcm-demo/app/src/main/res/values-w820dp/dimens.xml create mode 100644 sf-gcm-demo/app/src/main/res/values/colors.xml create mode 100644 sf-gcm-demo/app/src/main/res/values/dimens.xml create mode 100644 sf-gcm-demo/app/src/main/res/values/strings.xml create mode 100644 sf-gcm-demo/app/src/main/res/values/styles.xml create mode 100644 sf-gcm-demo/build.gradle create mode 100644 sf-gcm-demo/gradle.properties create mode 100755 sf-gcm-demo/gradlew create mode 100644 sf-gcm-demo/gradlew.bat create mode 100644 sf-gcm-demo/settings.gradle diff --git a/.gitignore b/.gitignore index 9f00b09..e70e33a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,13 @@ local.properties bin/ target gen/ +node/node_modules +sf-gcm-demo/build +sf-gcm-demo/google-services.json +sf-gcm-demo/gradle +sf-gcm-demo/app/build +sf-gcm-demo/app/gradle +sf-gcm-demo/app/google-services.json + diff --git a/bash/gcm_sender.sh b/bash/gcm_sender.sh new file mode 100644 index 0000000..b949a81 --- /dev/null +++ b/bash/gcm_sender.sh @@ -0,0 +1,6 @@ +server_api_key='server api key를 입력합니다.' +token='Instance ID의 token을 입력합니다.' +curl --header "Authorization: key=$server_api_key" \ +--header Content-Type:"application/json" \ +https://gcm-http.googleapis.com/gcm/send \ +-d "{\"data\":{\"title\":\"saltfactory GCM demo\",\"message\":\"Google Cloud Messaging 테스트\"},\"to\":\"$token\"} diff --git a/node/gcm_provider.js b/node/gcm_provider.js new file mode 100644 index 0000000..027f527 --- /dev/null +++ b/node/gcm_provider.js @@ -0,0 +1,26 @@ +var gcm = require('node-gcm'); +var fs = require('fs'); + +var message = new gcm.Message({ + collapseKey: 'demo', + delayWhileIdle: true, + timeToLive: 3, + data: { + title: 'saltfactory GCM demo', + message: 'Google Cloud Messaging 테스트', + custom_key1: 'custom data1', + custom_key2: 'custom data2' + } +}); + + +var server_api_key = 'Server API Key를 입력합니다.'; +var sender = new gcm.Sender(server_api_key); +var registrationIds = []; + +var token = 'Instance ID 의 token을 입력합니다.'; +registrationIds.push(token); + +sender.send(message, registrationIds, 4, function (err, result) { + console.log(result); +}); diff --git a/node/package.json b/node/package.json new file mode 100644 index 0000000..b1b5e34 --- /dev/null +++ b/node/package.json @@ -0,0 +1,8 @@ +{ + "name": "gcm-demo", + "version": "0.0.0", + "description": "", + "dependencies": { + "node-gcm":"latest" + } +} diff --git a/sf-gcm-demo/.gitignore b/sf-gcm-demo/.gitignore new file mode 100644 index 0000000..9c4de58 --- /dev/null +++ b/sf-gcm-demo/.gitignore @@ -0,0 +1,7 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/sf-gcm-demo/app/.gitignore b/sf-gcm-demo/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sf-gcm-demo/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sf-gcm-demo/app/build.gradle b/sf-gcm-demo/app/build.gradle new file mode 100644 index 0000000..8883cf8 --- /dev/null +++ b/sf-gcm-demo/app/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "net.saltfactory.demo.gcm" + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.google.android.gms:play-services-gcm:7.5.+' + compile 'com.android.support:appcompat-v7:22.1.1' + +} diff --git a/sf-gcm-demo/app/proguard-rules.pro b/sf-gcm-demo/app/proguard-rules.pro new file mode 100644 index 0000000..36cb415 --- /dev/null +++ b/sf-gcm-demo/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Projects/Libraries/adt-bundle-mac-x86_64/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/sf-gcm-demo/app/src/androidTest/java/net/saltfactory/demo/gcm/ApplicationTest.java b/sf-gcm-demo/app/src/androidTest/java/net/saltfactory/demo/gcm/ApplicationTest.java new file mode 100644 index 0000000..32ea580 --- /dev/null +++ b/sf-gcm-demo/app/src/androidTest/java/net/saltfactory/demo/gcm/ApplicationTest.java @@ -0,0 +1,13 @@ +package net.saltfactory.demo.gcm; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/sf-gcm-demo/app/src/main/AndroidManifest.xml b/sf-gcm-demo/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b77e809 --- /dev/null +++ b/sf-gcm-demo/app/src/main/AndroidManifest.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MainActivity.java b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MainActivity.java new file mode 100644 index 0000000..40412df --- /dev/null +++ b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MainActivity.java @@ -0,0 +1,144 @@ +package net.saltfactory.demo.gcm; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesUtil; + +public class MainActivity extends AppCompatActivity { + + private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; + private static final String TAG = "MainActivity"; + + private Button mRegistrationButton; + private ProgressBar mRegistrationProgressBar; + private BroadcastReceiver mRegistrationBroadcastReceiver; + private TextView mInformationTextView; + + /** + * Instance ID를 이용하여 디바이스 토큰을 가져오는 RegistrationIntentService를 실행한다. + */ + public void getInstanceIdToken() { + if (checkPlayServices()) { + // Start IntentService to register this application with GCM. + Intent intent = new Intent(this, RegistrationIntentService.class); + startService(intent); + } + } + + /** + * LocalBroadcast 리시버를 정의한다. 토큰을 획득하기 위한 READY, GENERATING, COMPLETE 액션에 따라 UI에 변화를 준다. + */ + public void registBroadcastReceiver(){ + mRegistrationBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + + if(action.equals(QuickstartPreferences.REGISTRATION_READY)){ + // 액션이 READY일 경우 + mRegistrationProgressBar.setVisibility(ProgressBar.GONE); + mInformationTextView.setVisibility(View.GONE); + } else if(action.equals(QuickstartPreferences.REGISTRATION_GENERATING)){ + // 액션이 GENERATING일 경우 + mRegistrationProgressBar.setVisibility(ProgressBar.VISIBLE); + mInformationTextView.setVisibility(View.VISIBLE); + mInformationTextView.setText(getString(R.string.registering_message_generating)); + } else if(action.equals(QuickstartPreferences.REGISTRATION_COMPLETE)){ + // 액션이 COMPLETE일 경우 + mRegistrationProgressBar.setVisibility(ProgressBar.GONE); + mRegistrationButton.setText(getString(R.string.registering_message_complete)); + mRegistrationButton.setEnabled(false); + String token = intent.getStringExtra("token"); + mInformationTextView.setText(token); + } + + } + }; + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + registBroadcastReceiver(); + + // 토큰을 보여줄 TextView를 정의 + mInformationTextView = (TextView) findViewById(R.id.informationTextView); + mInformationTextView.setVisibility(View.GONE); + // 토큰을 가져오는 동안 인디케이터를 보여줄 ProgressBar를 정의 + mRegistrationProgressBar = (ProgressBar) findViewById(R.id.registrationProgressBar); + mRegistrationProgressBar.setVisibility(ProgressBar.GONE); + // 토큰을 가져오는 Button을 정의 + mRegistrationButton = (Button) findViewById(R.id.registrationButton); + mRegistrationButton.setOnClickListener(new View.OnClickListener() { + /** + * 버튼을 클릭하면 토큰을 가져오는 getInstanceIdToken() 메소드를 실행한다. + * @param view + */ + @Override + public void onClick(View view) { + getInstanceIdToken(); + } + }); + + } + + /** + * 앱이 실행되어 화면에 나타날때 LocalBoardcastManager에 액션을 정의하여 등록한다. + */ + @Override + protected void onResume() { + super.onResume(); + LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, + new IntentFilter(QuickstartPreferences.REGISTRATION_READY)); + LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, + new IntentFilter(QuickstartPreferences.REGISTRATION_GENERATING)); + LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, + new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE)); + + } + + /** + * 앱이 화면에서 사라지면 등록된 LocalBoardcast를 모두 삭제한다. + */ + @Override + protected void onPause() { + LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver); + super.onPause(); + } + + + /** + * Google Play Service를 사용할 수 있는 환경이지를 체크한다. + */ + private boolean checkPlayServices() { + int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); + if (resultCode != ConnectionResult.SUCCESS) { + if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { + GooglePlayServicesUtil.getErrorDialog(resultCode, this, + PLAY_SERVICES_RESOLUTION_REQUEST).show(); + } else { + Log.i(TAG, "This device is not supported."); + finish(); + } + return false; + } + return true; + } +} diff --git a/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyGcmListenerService.java b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyGcmListenerService.java new file mode 100644 index 0000000..d1e4141 --- /dev/null +++ b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyGcmListenerService.java @@ -0,0 +1,66 @@ +package net.saltfactory.demo.gcm; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.NotificationCompat; +import android.util.Log; + +import com.google.android.gms.gcm.GcmListenerService; + +/** + * Created by saltfactory on 6/8/15. + */ +public class MyGcmListenerService extends GcmListenerService { + + private static final String TAG = "MyGcmListenerService"; + + /** + * + * @param from SenderID 값을 받아온다. + * @param data Set형태로 GCM으로 받은 데이터 payload이다. + */ + @Override + public void onMessageReceived(String from, Bundle data) { + String title = data.getString("title"); + String message = data.getString("message"); + + Log.d(TAG, "From: " + from); + Log.d(TAG, "Title: " + title); + Log.d(TAG, "Message: " + message); + + // GCM으로 받은 메세지를 디바이스에 알려주는 sendNotification()을 호출한다. + sendNotification(title, message); + } + + + /** + * 실제 디바에스에 GCM으로부터 받은 메세지를 알려주는 함수이다. 디바이스 Notification Center에 나타난다. + * @param title + * @param message + */ + private void sendNotification(String title, String message) { + Intent intent = new Intent(this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, + PendingIntent.FLAG_ONE_SHOT); + + Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_stat_ic_notification) + .setContentTitle(title) + .setContentText(message) + .setAutoCancel(true) + .setSound(defaultSoundUri) + .setContentIntent(pendingIntent); + + NotificationManager notificationManager = + (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + notificationManager.notify(0 /* ID of notification */, notificationBuilder.build()); + } +} diff --git a/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyInstanceIDListenerService.java b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyInstanceIDListenerService.java new file mode 100644 index 0000000..8cde9ec --- /dev/null +++ b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/MyInstanceIDListenerService.java @@ -0,0 +1,19 @@ +package net.saltfactory.demo.gcm; + +import android.content.Intent; + +import com.google.android.gms.iid.InstanceIDListenerService; + +/** + * Created by saltfactory on 6/8/15. + */ +public class MyInstanceIDListenerService extends InstanceIDListenerService { + + private static final String TAG = "MyInstanceIDLS"; + + @Override + public void onTokenRefresh() { + Intent intent = new Intent(this, RegistrationIntentService.class); + startService(intent); + } +} diff --git a/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/QuickstartPreferences.java b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/QuickstartPreferences.java new file mode 100644 index 0000000..92a9cf5 --- /dev/null +++ b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/QuickstartPreferences.java @@ -0,0 +1,12 @@ +package net.saltfactory.demo.gcm; + +/** + * Created by saltfactory on 6/8/15. + */ +public class QuickstartPreferences { + + public static final String REGISTRATION_READY = "registrationReady"; + public static final String REGISTRATION_GENERATING = "registrationGenerating"; + public static final String REGISTRATION_COMPLETE = "registrationComplete"; + +} diff --git a/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/RegistrationIntentService.java b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/RegistrationIntentService.java new file mode 100644 index 0000000..77fbaa5 --- /dev/null +++ b/sf-gcm-demo/app/src/main/java/net/saltfactory/demo/gcm/RegistrationIntentService.java @@ -0,0 +1,61 @@ +package net.saltfactory.demo.gcm; + +import android.annotation.SuppressLint; +import android.app.IntentService; +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import com.google.android.gms.gcm.GoogleCloudMessaging; +import com.google.android.gms.iid.InstanceID; + +import java.io.IOException; + +/** + * Created by saltfactory on 6/8/15. + */ +public class RegistrationIntentService extends IntentService { + + private static final String TAG = "RegistrationIntentService"; + + public RegistrationIntentService() { + super(TAG); + } + + /** + * GCM을 위한 Instance ID의 토큰을 생성하여 가져온다. + * @param intent + */ + @SuppressLint("LongLogTag") + @Override + protected void onHandleIntent(Intent intent) { + + // GCM Instance ID의 토큰을 가져오는 작업이 시작되면 LocalBoardcast로 GENERATING 액션을 알려 ProgressBar가 동작하도록 한다. + LocalBroadcastManager.getInstance(this) + .sendBroadcast(new Intent(QuickstartPreferences.REGISTRATION_GENERATING)); + + // GCM을 위한 Instance ID를 가져온다. + InstanceID instanceID = InstanceID.getInstance(this); + String token = null; + try { + synchronized (TAG) { + // GCM 앱을 등록하고 획득한 설정파일인 google-services.json을 기반으로 SenderID를 자동으로 가져온다. + String default_senderId = getString(R.string.gcm_defaultSenderId); + // GCM 기본 scope는 "GCM"이다. + String scope = GoogleCloudMessaging.INSTANCE_ID_SCOPE; + // Instance ID에 해당하는 토큰을 생성하여 가져온다. + token = instanceID.getToken(default_senderId, scope, null); + + Log.i(TAG, "GCM Registration Token: " + token); + } + } catch (IOException e) { + e.printStackTrace(); + } + + // GCM Instance ID에 해당하는 토큰을 획득하면 LocalBoardcast에 COMPLETE 액션을 알린다. + // 이때 토큰을 함께 넘겨주어서 UI에 토큰 정보를 활용할 수 있도록 했다. + Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE); + registrationComplete.putExtra("token", token); + LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete); + } +} diff --git a/sf-gcm-demo/app/src/main/res/drawable-hdpi-v11/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-hdpi-v11/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..db2441bd36bd0fe2daf9891a6b45fc1ed3944375 GIT binary patch literal 659 zcmV;E0&M+>P)RK+oirC=w=$GBctSB_c^C z$}2?%L?l1nv$S6O)P48vbI(5K{&?@zU6XsdXYaK>d+oK>Ui*k?CYokEGzBuVIl#E2 zf9(P{Gq>3%>2FMDE|8hc0$u>mfFqKuRj2?n0&E60NgA)$Sp>8XxCX42^tKH^D}gt_ zQQ&$hAUAGii-L!i1O1YIWl&+YbAiQxkMrk0z&GHFKi7KI%=&!!Yq8Re` zYk=3l5O4{Y53C1H0($`8+IsPry8~PRUIIUXL%>yFga4NomxWnoX1?-sz$xGaFbvEq zv3(xA$AQZM@Qft)WK>dse9S7~72sLdimY=z%@QPK%Up?PTf4+F>}eiU5zsc^AvCX7 zB}qNLc1XHkDyYqDZ3xKOB@LzwAM;uy>3LEeGP8xiJ76G1d&M!IffbUz*UoR)vQS@6 z1LrFmDl_e@XK-yi#ekLq??a(0qrA%4-@u@xPub)c(BW`gR54Ix&XA;wQJ_%X9{`?R z-I7PZc1a%SlhfJE`T-BNZp#u$6Lu$UnVI=H?<*#1Hg?b@X#?y-r6+8(0<@%4+wf5DvE-hhk70=@<7r1nG-|1f!jsP z>A?Ggk|qjr{b|1pc5KpX002ovPDHLkV1oUxDeeFO literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-hdpi/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-hdpi/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..3cbd048ea04e844138357a74e52b8c961f59028a GIT binary patch literal 764 zcmV7@+uSmjIm~>Bd7exp5}zAOdpsx>i#G`&H@fT@C ztO39W0C=ml-qc#(QcB%UCX?&U^6uNF`F!41N);^28qr#xQc6)%_@F^41xl$$2>B+Z zT;1K>y~8<|&9Qp`IOi-Lk53389w?>y!+5|L+psL_ex*`*#W`2|B;uTt-rnAaN~ya- z2ok1vBi6QUO(}h}y}ivj=K<}2fziHHDvc_o@>0q(hbi93u`FwY5RynF5^szb0YEmJ zJx3{B6+&F}eLpbrD03_p`zWQnHZwExB>-4lTujyL^(X%_Gb|%Q2-voravUd(#@O!e z?$@sCjvlr1=6uGO*;Usuolf@=Lf&bu2ah7l-_21<*L>fn47;wo?E8LKE8{}0S7Wi*I2r&cWm_b&Eb9+II~WAJD3i%t zuGMNQh!_uX4*ust{K^;`!}DJ%+7n4xtAC?IJ2h!Qd(0|O=u3`~?_CIbdi$|aGBavLZ)C8IN; zO#B1RfO0Q9dbHo&KKr!K-p)BDvg#eYt#_^OdVcG9*NVSv>C9hBsqZWCI?1O$VV6?o zVi|^$lqR+tFdY~09M?KO91qqiY(G}xXp$ej02R0nCvhAvF$>GF6bn$Rdxtl8g>NnY zIh;xIth1O=C#a56%1oTXDm=m_tik-QQ@n4T^f9*J1x_dV-Vab^I)by9JzyWc-~=vq z%2Q*zdoT?LTgkgC?#HUKRmhbjKYR6HE3RT;zid7HBRG)c!5Ba(WeM(L?F5rIVMExN z_*91K5t6{{bDk z{eu#1z-=t*cRdF5*P*v7$?)u> kpObtYvv4L__IPo>07)pF86mYE$^ZZW07*qoM6N<$f?>GVasU7T literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-mdpi/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-mdpi/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..105b2d730bf1f7565a4a86365c3beee787fea772 GIT binary patch literal 499 zcmVX1^@s6IQ*`u0005HNklxlaM)N_USnYqY`wyegaj8N*IZyo6EsBPhHOY@Yh}tS z1;IkG^Iy0|EG*=9c4ueinAOO61Y@*wV0g^D_dfI9m&X8l|g5VnfT$an_ z>*sVC4u^TI^-{H3{bl1GHSm3Zol?47DwTd%M-T)HQp!&lV-tqq??$8X$KH=dqg}1_ zS*21LKLK#gaW0qZF~;tUF)IM@RVjrX$FXq60NU+#E|bX| zB81ko)<`LZ000?dQfoKH*q+D6m`%^~ZXW@hb2p#Q9|0ZEygrF_U3Uk1z1~kD1fKyg)BKDv4&83IDWz<^rUFW7GX=zP z{3-w;O*002ovPDHLkV1n+6*X{rS literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-xhdpi-v11/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-xhdpi-v11/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..d071e8fecc5ff371e0bc1398efad1824c59bcc9b GIT binary patch literal 979 zcmV;^11$WBP)yWhJFui)|?+;h+Q|EfB5s!kcb zT&$PlCl`SbLSNv6nT1*q4j~9vA2a(eYrRYYA%uRwX5a>JBG05*i>AE~A@l(j0uz9B zX7+E|_&fxL0JnfIfF|Itp0q>=VH|K9cnExLX01gD3s02>bRi84Aq)Vf04ISLfEIcrAinS*V4{y10gMEO1A~2`HsC4n#D6aXSAaGF^i4Yo zI1da1z5_00XyXgKRbbafZXH|un5@g?(-(k zUdvjn(+fP5eghow4Sfoj=Nc=rC7uJnxZl4576aGwM!Vbu+?8a7Z9q#A#3|n%1Xh{Z z>%8;lCJ;i9pRWSsF8bdS(hlqZwgTZ( zX3Cd3BuYSs*EwKvNeQTmn_*_kT4M<)O}++R+ui?9yMRl>H|7v!t zSI`>0UQD~(t@HwF4L+)i4l+qSvwDLoY`9)e;3I5)RY1*3k-z`|002ovPDHLkV1lxg BnAiXS literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-xhdpi/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-xhdpi/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..f749b60a7a93e2dfe938dbf27dfe4931b05a9151 GIT binary patch literal 1058 zcmV+-1l{|IP)-FiqM1ZIBo z`+a|(?=NrO3q@5-u$*>6B9YaK3v4 zl*?rzrTkM$d2woL>e5j~sN&^vISC>B7y$6-?a%{hM|o6X+oYJmz+7jAEFpT!t& z5<<@H?CfkM5{Z`~gzrHJUz1WkEQIiKNhtw@(EB2UDpJaC5JI2FVzKXccX!X&wtZDf zd2W1se9Ld7D*+WyC=>=EgkKnj@hn1UM+otZ<2ZnG-YV)Bzx$UEqKE*D@h_b7Q30l7ur)cQ9{%yTpe>0oSHoDG$>O7H1+^{U`Mb$wk%!)`a#}7n&=eq8z zhe@u;q}sjZd;%KKO>c7-wab~i7>I3JBhub8I!u9^jp0Ht(bXlUp*=lr4L#P8cc2&n=9 z#%5<{El)tHRC?OB?VAsxxG!RGaPWy_GWn}7;Jjs7Uxk4;XpU$!`c68XzUm2BUtiBK z#)?5N4kJ#}w9L%R%qO0JVzHRr+uOSc)qPamb9-Fr4&r;dju3JolgSi40jsO43$E*~ zgwa{h9Ga#rRIAms76Has{y%o^?FD)rV2trXqtVzGP$(3#ob!CINsbb)>-s+glmORt z^Fi^25f_O>+6kPv0LO72=nQlua1>8_9YjJ%y9J6s7~TfW@&6K#&*xK)i(fxk+ zZy8W_i#vQ?O4$@bd@Y3dO+6>Jwqys-eIy=_AL~mC(==r+mvj8*$73xPz>5Bh%07WU cfs-fjH&Co!>ZR>R+5i9m07*qoM6N<$g1PhgjQ{`u literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-xxhdpi-v11/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-xxhdpi-v11/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..79dd369abfcc757252b7821d9427c54a192753b8 GIT binary patch literal 1768 zcmVP)gy6oCIp=OdJ-QM|YChcw)POQ9q%@#3 zO_L-^(m}AmUaqw;AioS)2v{2U2bhs0$-iR}RGOv>0E+{Q0MmgvMJKfkAmN+<91DB| z+y;D-B+1;d1S#OG51ayQ4Lk_knIwsmntPN1MO9GvGX658x-j z3m6xoow>S&8~FXr*U)(1{CVHIWad4m5^!W#_^QAwz?H!Jz|5ixN?|~ndYYyRwU)CV za5}I7@H%i4@M4lAb6Q=Z3CM!6s`&ZUfz<$SWLaRb_}pw@sxuD!0DPy$0e^>{v;`K| zwGD7Fu&Wjg+^YMBMh?5KEY~dy$j^B*YXWBj2gwb1C`5aTGt~seWp*WC(^ye929}JM z*67P)gy&FHg)uW;Gqg0pw>D?3IBdfRn;yo{wc;3)vmm5Lhpu6akWT?62WMTGdMd$+oL&oi-T2v1?o z6!=aT*b|_Dq!sB(M%E_-YxI*wj&tjRcN;ZpRYjNe5!0Z6(-7Y_K)kK+vygrf$jPo>?g6rg~!Oo;Glz!sr7 z{kYk(=QNi30Jt4^7MNB>iwXk@IHo!dh?UET+Q4xv4g*6o4(ick3VBgTWdOMpSp8vPE!Fb;Yq8^AHZ z)L9R*T>*vln9#ZpFjCglsxYihHa=C(4X?zp0+>_n3s3V}J zh}kTmvCp7uPwV71v}h zKxP;x0*AE=7&`$n875V;hE-kS8?36XvZ@<~=U2 zWsdaun!nd{tPNHcA*SX5WI0(tj{~-nSVFGy5Rm1ey@~>|r)Jw03#uY00ohz-%bpfA zPwJzci#1!&cK;JVw$L;zC^sNQT0m77X)UM}AS;nJCDeeLg(cFgigXRArNeZHQw=D; zNY@rrThNfx)FPb`yw!keK)uEHwFT7{R9jGQ1ZoTFjbE)nwFT7{)Ej}?f_mep2E7aH zoj0RsmeF*_Be6N9YJEYiIIU{DRU~OIAnRgR$3{8Zf2%y~>TplJI|qjC=jc>=Hj8Li znLC+ny)#c;#bN&0?hdP}6Wi^n?*z#G7w#*yaok2n>+|+2W_HC62u15`HgdWL*1VU7 z;4eoE``LDfmsm4v$&6`-7TNuNDo} zBR9_ZURU#mMjBGT46hw@|4-Kvl8p;$kh>DwwgP9h0sD8GsdPF29V9rNpb!0$LqO7{ z=6370&ut0O7Spep9`*BPZ9!;UP;Nk@eg|XZ3u{0b6Hx=o0Q4UMuYqUmGmb$30000< KMNUMnLSTX(dN;iQ literal 0 HcmV?d00001 diff --git a/sf-gcm-demo/app/src/main/res/drawable-xxhdpi/ic_stat_ic_notification.png b/sf-gcm-demo/app/src/main/res/drawable-xxhdpi/ic_stat_ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..c1985da3ef528308bfe4ccbeca20c3903483e6e3 GIT binary patch literal 1763 zcmV<91|0c`P)Fr|4{D4tF{nXmpbZf;L84VcH<4IqeA%IxG*D=9 z1C{zHP?3rWN_arjpbttgnqV~HrfAUCwi|BU&d!{hIknqRy0__0SxR=2&2Bp9{OAAv z@B9CAD+DwAfiv8HPy$eF21^W-7$`6TB?%Q6z=FG%7$`V|1sW(ZP+$NH?p|V`;1CvQ zASVL{4jjM@4Gp}&ai-K=ja^?~FCc_6lYxu?q?E9$tLtHm@yigxgMEE{CoRhoQ}V=P zCpGr&-Mbe;2an92_e5yN*6~WkwK5XOsRQiXJ zx~~c$dN}9JH8nMZ*@{TcDx{27R8%~|IscdtGEdXAr2_*4N21Xv@9OFb3L)+ygglK9 zS|x;7B&Ebc2q2{#{ip{*IQl^dsc#M;{E>71k(BayB9ZuO!-fsRy}i9?XlQ6LrSuEV z`QHekl?b5|kx0bJroNm2R0MbI*l`Ev{0#_U)G&;GjPV-I`2!f^XQY%*2_f!uU3c7R z<*af((>KN#5JG^aX_ti%UrQ;!0Ra320Qk_h?F9&-?T+JYYiVh@oK140!O17LRAQBv zm)|3$+>a1?$S{n50RZKc(sIsuR%dg8(KJmllfW2Xwr#r#0B{x|w0zE-IcM^jfAR%@ zX3d&aEri$t09ct1Xs>Oq1NsReWW%LPmoDZr@8kq9HXqbTDYsEdUto;sUY+yO9%D>( zUH?)_`S#Gz(79Y7vI0>0kHunl>$-l}w(VLW1kR@ITyn|xJt2hay8fFGVsShk@6QGz z>r!Ip&Yd+Fg!#D>3cy8_5wdXxACEDBDt4!0}olGWQRHf02 z4E$;fArz)*9uq>WZfa`!C!O8240LyQYm`#Ub=`M3=hLeBTwpQAu3E-mj9b$!VC^@e}cQ{QDd8VG@AO&dzF0(+=6Ty)ajFZsz+yAn=Qn z^7%+4a`F0cCjd}upMimaHLmM+GRDgMil85M002qTG+V2xsN|ks$ zj6K@i+?*H(pyboh(Qz;5{IvR`-`e%lp4wBW4O1i%Ij3YaDj`*U`uqEr+O~bL7_#s> zrfHhXX3w5|NL8az080NOBO@)Y>$Z9|R*d$BVYHg2`JS4YM*+lQF@rJo0i|@cpL9=G zF6p|y_v+QFuUnRt90g!mR-nARyoWLNQZXXxbxcCY5eVV(_3PK$DF9`mP-qY5{8^RI zW06xoG9|PufT@hfg!uv?gnTzVJltSe*2wh$_A|zoOc(8b+Qk@uC8b=dO6fR&U@)l8 zVV33_g<`hD7#{-w)J*^o3WfGD#_EdcSiWPY1yEL2woeFASAe!No&)(QALSn*Bs~L^ z(mKBfn+|&jp<@uji4sx_aL#9pgl<0orfJTo94IkR%xa~oP+A7mJTM(q!*8%^9+(6` z<-km-LTMSeZ29QG;14nGzt{-1cs~wqb+Y!c?x{bW$ zA3{irZQJjU@5t1q{`~p#bJf)*0ASHAj^HFhXvO^b^Zy**)GLRTjFQRZT+aCljPaA4 zb4?v#s4LSce5<=*wK|nk>_2H-DWy8dIw6GE8w!PfSKG-62U}wo)&>Be%rwma002?? z|E9kfkEUr8ww{zyi4aP + +