I got below error when impliment GCM - android

i have try to implement GCM in android studio got below error in my logcat.
LogCat:
onReceive: com.google.android.c2dm.intent.REGISTRATION GCM
IntentService class: com.project.GCMIntentService Acquiring wakelock
manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.project">
<permission
android:name="com.project.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" ></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.project.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.project.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<!-- Required OpenGL ES 2.0. for Maps V2 -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<permission
android:name="com.project.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<application
android:name="com.project.App"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#style/AppTheme">
<activity
android:name=".SplashScreenActivity"
android:screenOrientation="portrait"
android:theme="#style/FullScreenThemes">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.project.core.account.ManageAccounts" />
<activity android:name=".projectActivity"/>
<activity android:name=".projectLogin"/>
<activity android:name="fieldatom.controls.SearchableItemActivity" />
<activity android:name="com.project.SettingsActivity" />
<activity
android:name="com.project.core.account.AppIntro"
android:screenOrientation="portrait" />
<activity
android:name=".base.addons.mail.widget.MailDetailDialog"
android:theme="#style/Theme.AppCompat.Light.Dialog" />
<activity
android:name=".base.addons.mail.widget.MailChatterCompose"
android:theme="#style/Theme.AppCompat.Light.Dialog" />
<activity
android:name=".core.account.FieldAtomAccountQuickManage"
android:theme="#style/Theme.AppCompat.Light.Dialog"
android:windowSoftInputMode="adjustPan" />
<activity android:name="com.project.core.account.About" />
<activity android:name="com.project.core.account.Profile" />
<!-- Reminder Receivers// -->
<receiver android:name="com.project.core.utils.reminder.ReminderReceiver" />
<receiver android:name="com.project.core.utils.reminder.ReminderActionReceiver" />
<!--<receiver android:name=".server.notifications.OdooServerNotificationReceiver">
<intent-filter>
<action android:name="com.project.odoo.mobile.SERVER_NOTIFICATION" />
</intent-filter>
</receiver>-->
<service android:name="com.project.core.auth.OdooAuthService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="#xml/authenticator" />
</service>
<provider
android:name="com.project.core.orm.provider.BaseModelProvider"
android:authorities="com.project.core.provider.content"
android:multiprocess="true" />
<provider
android:name="com.project.base.addons.ir.providers.IrModelProvider"
android:authorities="com.project.core.provider.content.sync.ir_model"
android:multiprocess="true" />
<!-- Sync Customer Provider & Service // -->
<provider
android:name="com.project.addons.customers.providers.CustomersSyncProvider"
android:authorities="com.project.core.provider.content.sync.res_partner"
android:label="#string/sync_label_customers"
android:multiprocess="true" />
<service
android:name="com.project.addons.customers.services.CustomerSyncService"
android:exported="true"
android:process=":sync_customer">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/customer_sync_adapter" />
</service>
<!-- Sync Request Provider & Service // -->
<provider
android:name="com.project.addons.requests.providers.RequestSyncProviders"
android:authorities="com.project.core.provider.content.sync.fa_service_request"
android:label="#string/sync_label_request"
android:multiprocess="true" />
<service
android:name="com.project.addons.requests.services.RequestSyncService"
android:exported="true"
android:process=":sync_request">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/request_sync_adapter" />
</service>
<!-- Sync Stage Provider & Service // -->
<provider
android:name="com.project.addons.stages.providers.StageSyncProviders"
android:authorities="com.project.core.provider.content.sync.fa_service_stage"
android:label="#string/sync_label_stages"
android:multiprocess="true" />
<service
android:name="com.project.addons.stages.services.StageSyncService"
android:exported="true"
android:process=":sync_stage">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/stage_sync_adapter" />
</service>
<!-- Sync Account Analytic Provider & Service // -->
<provider
android:name="com.project.addons.accountanalytics.providers.AccountAnalyticSyncProviders"
android:authorities="com.project.core.provider.content.sync.account_analytic_line"
android:label="#string/sync_label_accountAnalytic"
android:multiprocess="true" />
<service
android:name="com.project.addons.accountanalytics.services.AccountAnalyticSyncService"
android:exported="true"
android:process=":sync_account_analytic">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/account_analytic_sync_adapter" />
</service>
<!-- Sync Product Provider & Service // -->
<provider
android:name=".addons.products.providers.ProductsSyncProviders"
android:authorities="com.project.core.provider.content.sync.product_product"
android:label="#string/sync_label_product"
android:multiprocess="true" />
<service
android:name=".addons.products.service.ProductsSyncService"
android:exported="true"
android:process=":sync_account_analytic">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/product_sync_adapter" />
</service>
<!-- Sync QUOTATION Provider & Service // -->
<provider
android:name=".addons.quotes.providers.QuotationSyncProviders"
android:authorities="com.project.core.provider.content.sync.sale_order"
android:label="#string/sync_label_quotation"
android:multiprocess="true" />
<service
android:name=".addons.quotes.services.QuotationSyncService"
android:exported="true"
android:process=":sync_quotation">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/quote_sync_adapter" />
</service>
<!-- Sync QUOTATIONLine Provider & Service // -->
<provider
android:name=".addons.quotes.providers.QuotationLineSyncProviders"
android:authorities="com.project.core.provider.content.sync.sale_order_line"
android:label="#string/sync_label_quotation_line"
android:multiprocess="true" />
<service
android:name=".addons.quotes.services.QuotationLineSyncService"
android:exported="true"
android:process=":sync_quotation_line">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/quote_line_sync_adapter" />
</service>
<!-- Sync Attachment Provider & Service // -->
<provider
android:name=".addons.attachment.providers.IrAttachmentSyncProviders"
android:authorities="com.project.core.provider.content.sync.ir_attachment"
android:label="#string/sync_label_attachment"
android:multiprocess="true" />
<service
android:name=".addons.attachment.service.IrAttachmentSyncService"
android:exported="true"
android:process=":sync_attachment">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/attachment_sync_adapter" />
</service>
<!-- Sync MailMessage Provider & Service // -->
<provider
android:name=".base.addons.mail.providers.MailMessageSyncProviders"
android:authorities="com.project.core.provider.content.sync.mail_message"
android:label="#string/sync_label_mail_message"
android:multiprocess="true" />
<service
android:name=".base.addons.mail.service.MailMessageSyncService"
android:exported="true"
android:process=":sync_mail_message">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/mail_message_sync_adapter" />
</service>
<!-- Sync Maps Provider & Service // -->
<provider
android:name=".addons.maps.providers.MapsSyncProviders"
android:authorities="com.project.core.provider.content.sync.fa_map"
android:label="#string/sync_label_map_message"
android:multiprocess="true" />
<service
android:name=".addons.maps.service.MapsSyncService"
android:exported="true"
android:process=":sync_map">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="#xml/maps_sync_adapter" />
</service>
<service android:name=".addons.requests.services.TimeUpdateService"></service>
<activity
android:name="com.project.addons.customers.CustomerDetailActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden|adjustPan" />
<activity
android:name=".addons.requests.utils.RequestTabDetailAcitivty"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden|adjustPan"
/>
<activity
android:name=".addons.accountanalytics.VisitDetailActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:theme="#style/CustomActionBar"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".addons.accountanalytics.CreateVisitActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.requests.AddPartActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.requests.AddNoteActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.requests.AddQuoteActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.requests.utils.CaptureSignature"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.requests.utils.ProductRequestListActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.quotes.QuoteDetailActivity"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<activity
android:name=".addons.products.ProductDetails"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:windowSoftInputMode="stateHidden"></activity>
<!-- Map Related Metadata -->
<uses-library
android:name="com.google.android.maps"
android:required="false" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="AIzaSyCpjJtPYoeVN2dGqCVMCDEoR847OEwzgME" />
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<!-- Push Notification -->
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.project" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService"></service>
</application>
<!--CB:A6:E7:26:97:08:37:4A:D6:60:1B:9B:2C:D0:9A:3B:9F:DF:02:D3;com.project-->
</manifest>
This is my project structure details below.
com.projcet
App.java
ProjcetLogin.java
GCMIntentService.java

This code working perfect in eclipse & android studio...finally i can do it.
MainActivity.java
public class MainActivity extends Activity implements View.OnClickListener{
//Notification Constant
Context context;
Button btn_GCMRegister, btn_Post;
GoogleCloudMessaging gcm;
public static String URL = "192.168.1.39:12069";
String regId;
public final String GOOGLE_PROJECT_ID = "your project id";
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = getApplicationContext();
init();
}
private void init() {
btn_GCMRegister = (Button) findViewById(R.id.btn_gcm_register);
btn_GCMRegister.setOnClickListener(this);
btn_Post = (Button) findViewById(R.id.btn_post_on_server);
btn_Post.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_gcm_register:
registerGCM();
break;
case R.id.btn_post_on_server:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Map<String, Object> params = new HashMap<String, Object>();
params.put("regId", regId);
params.put("user_id", 1);
String server_url = URL;
try {
post(server_url, params);
}catch (IOException e){
e.printStackTrace();
}
break;
default:
break;
}
}
/*
* Issue a POST request to the server.
*/
private static void post(String endpoint, Map<String, Object> params)
throws IOException {
URL url;
try {
url = new URL(endpoint);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("invalid url: " + endpoint);
}
StringBuilder bodyBuilder = new StringBuilder();
Iterator<Map.Entry<String, Object>> iterator = params.entrySet().iterator();
// constructs the POST body using the parameters
while (iterator.hasNext()) {
Map.Entry<String, Object> param = iterator.next();
bodyBuilder.append(param.getKey()).append('=')
.append(param.getValue());
if (iterator.hasNext()) {
bodyBuilder.append('&');
}
}
String body = bodyBuilder.toString();
//Log.v(Config.TAG, "Posting '" + body + "' to " + url);
byte[] bytes = body.getBytes();
HttpURLConnection conn = null;
try {
Log.e("URL", "> " + url);
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setFixedLengthStreamingMode(bytes.length);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
// post the request
OutputStream out = conn.getOutputStream();
out.write(bytes);
out.close();
// handle the response
int status = conn.getResponseCode();
System.out.println("Json Data--->" + status);
// If response is not success
if (status != 200) {
throw new IOException("Post failed with error code " + status);
}
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
private void registerGCM() {
// TODO Auto-generated method stub
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regId = gcm.register(GOOGLE_PROJECT_ID);
Log.d("Reg Id----->", "" + regId);
Toast.makeText(MainActivity.this,"Register Key from server : " +regId,Toast.LENGTH_LONG).show();
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
Log.d("MainActivity", "Error: " + msg);
}
Log.d("MainActivity", "AsyncTask completed: " + msg);
return msg;
}
#Override
protected void onPostExecute(String msg) {
Toast.makeText(getApplicationContext(),
"Registered On GCM Server." + msg, Toast.LENGTH_LONG)
.show();
}
}.execute(null, null, null);
}
}
GCMIntentService.java
public class GCMIntentService extends GCMBaseIntentService {
#Override
protected void onError(Context arg0, String arg1) {
// TODO Auto-generated method stub
Log.e("onError", "gcm...error");
}
public GCMIntentService() {
super("your project id");
}
#Override
protected String[] getSenderIds(Context context) {
return super.getSenderIds(context);
}
#Override
protected void onMessage(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.i(TAG, "Received message");
if (intent.getExtras() != null) {
String message = intent.getExtras().getString("message");
String title = intent.getExtras().getString("title");
String ticker = intent.getExtras().getString("ticker");
generateNotification(context,message,title,ticker);
}
}
#Override
protected void onRegistered(Context arg0, String arg1) {
// TODO Auto-generated method stub
Log.e("onRegistered", "gcm Registered");
}
#Override
protected void onUnregistered(Context arg0, String arg1) {
// TODO Auto-generated method stub
Log.e("onUnregistered", "gcm...Unregistered...");
}
/**
* Create a notification to inform the user that server has sent a message.
*/
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void generateNotification(Context context, String message,String title,String ticker) {
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(context);
Intent notificationIntent = new Intent(context, MainActivity.class);
PendingIntent intent = PendingIntent.getActivity(context, 0,
notificationIntent, 0);
builder.setContentTitle(title)
.setContentText(message)
.setLargeIcon(
BitmapFactory.decodeResource(context.getResources(),
icon))
.setStyle(new Notification.BigTextStyle().bigText(message))
.setContentIntent(intent).setSmallIcon(icon).setTicker(ticker)
.setLights(0xff00ff00, 300, 100)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE).setAutoCancel(true).setWhen(when);
Notification notification = builder.build();
notificationManager.notify(0, notification);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxx.gcmnotification" >
<!-- GCM connects to Internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Creates a custom permission so only this app can receive its messages. -->
<permission
android:name="com.example.xxx.gcmnotification.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.xxx.gcmnotification.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.example.xxx.gcmnotification" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
</application>
</manifest>
build.gradle(Module:app)
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.google.android.gms:play-services:+'
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:orientation="vertical"
android:gravity="center"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:id="#+id/btn_gcm_register"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:text="Register On GCM Server" />
<Button
android:id="#+id/btn_post_on_server"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:text="Post On Server" />
</LinearLayout>

Related

Parse-Android ; Unable to receive 'action' in custom ParseBroadcastReceiver

Im sending a push message with a custom action but in the onPushReceive the action that I get is com.parse.push.intent.RECEIVE instead of com.hellboy.beat.STATUS_DONE
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hellboy.beat"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- permission required to use Alarm Manager -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<!-- permission required for Notification -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- permission required to Send SMS -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- permission required to get Location & Number -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- permission required to Vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- permission required to use Parse -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- permission required to use Parse Push -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="com.parse.starter.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.hellboy.beat.permission.C2D_MESSAGE" />
<application
android:name="com.hellboy.beat.Application"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.hellboy.beat.main.Activity_main"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.hellboy.beat.login.Activity_login" />
<activity android:name="com.hellboy.beat.requests.Activity_requests" />
<activity android:name="com.hellboy.beat.settings.Activity_settings" />
<!-- Register the Notification Receiver -->
<service android:name="com.parse.PushService" />
<!-- Regular Push Notification -->
<receiver android:name="com.parse.ParseBroadcastReceiver" />
<!-- Our Reciver -->
<receiver
android:name="com.hellboy.beat.PushRec"
android:exported="false" >
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.hellboy.beat.STATUS_DONE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver
android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<!-- IMPORTANT: Change "com.parse.starter" to match your app's package name. -->
<category android:name="com.hellboy.beat" />
</intent-filter>
</receiver>
</application>
</manifest>
PushRec.java
public class PushRec extends ParsePushBroadcastReceiver
{
private static final String TAG = "BEAT_PUSHREC";
Context context;
#Override
public void onPushReceive(Context context, Intent intent)
{
this.context = context;
Log.i(TAG, "Receiver");
if (intent == null)
{
Log.i(TAG, "Receiver intent null");
}else
{
Log.i(TAG, "Receiver intent not null");
String action = intent.getAction();
Log.i(TAG, "got action " + action );
if (action.equals("com.hellboy.beat.STATUS_DONE"))
{
//DOES NOT COME OVER HERE
}
}
}
}
Sending-Push:
ParseQuery<ParseInstallation> pushQuery = ParseInstallation.getQuery();
pushQuery.whereMatchesQuery("user", subscriberQuery);
JSONObject obj=null;
obj =new JSONObject();
try
{
obj.put("action","com.hellboy.beat.STATUS_DONE");
obj.put("statusdone_message" , message);
} catch (JSONException e1) {
e1.printStackTrace();
}
//TODO move this to the 'cloud'
ParsePush pPush = new ParsePush();
pPush.setQuery(pushQuery);
pPush.setData(obj);
pPush.sendInBackground();
NOTE: My understanding is I'm making a mistake in the Manfiest since the notification arrives, but the wrong action is called
You can override onReceive method to dispatch your custom action.
#Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
switch (intentAction) {
case "com.hellboy.beat.STATUS_DONE":
onPushReceive(context, intent);
break;
case ACTION_PUSH_DELETE:
onPushDismiss(context, intent);
break;
case ACTION_PUSH_OPEN:
onPushOpen(context, intent);
break;
}
}
https://github.com/ParsePlatform/Parse-SDK-Android/blob/master/Parse/src/main/java/com/parse/ParsePushBroadcastReceiver.java
The error was in the Manifest; ParseBroadcastReceiver should be ParsePushBroadcastReceiver
Snippet:
<receiver
android:name="com.parse.ParsePushBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name="com.hellboy.beat.PushRec" >
<intent-filter>
<action android:name="com.hellboy.beat.STATUS_DONE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
And remove this from the Manifest:
<!-- Regular Push Notification -->
<!-- REMOVE THIS -->
<receiver android:name="com.parse.ParseBroadcastReceiver" />
Also in the Receiver:
public class PushRec extends ParsePushBroadcastReceiver
{
}
becomes
public class PushRec extends BroadcastReceiver
{
}

Attempt to invoke virtual method 'void com.pushbots.push.utils.PBPrefs.setCustomHandler(java.lang.String)' on a null object r

I am use push bots API for push notification i got exception null pointer when i try to implement Custom handler for notifications.
Here is documentation where i learn
https://pushbots.com/developer/docs/android-sdk-integration
My Android manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.assorttech.assorttech" >
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission android:name="com.assorttech.assorttech.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.assorttech.assorttech.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive dataf message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="com.assorttech.assorttech.MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.thefinestartist.finestwebview.FinestWebViewActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="sensor"
android:theme="#style/FinestWebViewTheme.Light"
>
</activity>
<receiver
android:name="com.pushbots.google.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.assorttech.assorttech" />
</intent-filter>
</receiver>
<receiver android:name="com.pushbots.push.DefaultPushHandler" />
<!--<receiver android:name="com.assorttech.assorttech.customHandler" />-->
<service android:name="com.pushbots.push.GCMIntentService" />
</application>
</manifest>
public class customHandler extends BroadcastReceiver
{
private static final String TAG = "customHandler";
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
Log.d(TAG, "action=" + action);
// Handle Push Message when opened
if (action.equals(PBConstants.EVENT_MSG_OPEN)) {
//Check for Pushbots Instance
Pushbots pushInstance = Pushbots.sharedInstance();
if(!pushInstance.isInitialized()){
// Log.d("Initializing Pushbots.");
Pushbots.sharedInstance().init(context.getApplicationContext());
}
//Clear Notification array
if(PBNotificationIntent.notificationsArray != null){
PBNotificationIntent.notificationsArray = null;
}
HashMap<?, ?> PushdataOpen = (HashMap<?, ?>) intent.getExtras().get(PBConstants.EVENT_MSG_OPEN);
Log.w(TAG, "User clicked notification with Message: " + PushdataOpen.get("message"));
//Report Opened Push Notification to Pushbots
if(Pushbots.sharedInstance().isAnalyticsEnabled()){
Pushbots.sharedInstance().reportPushOpened( (String) PushdataOpen.get("PUSHANALYTICS"));
}
//Start lanuch Activity
String packageName = context.getPackageName();
Intent resultIntent = new Intent(context.getPackageManager().getLaunchIntentForPackage(packageName));
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_CLEAR_TASK);
resultIntent.putExtras(intent.getBundleExtra("pushData"));
Pushbots.sharedInstance().startActivity(resultIntent);
// Handle Push Message when received
}else if(action.equals(PBConstants.EVENT_MSG_RECEIVE)){
HashMap<?, ?> PushdataOpen = (HashMap<?, ?>) intent.getExtras().get(PBConstants.EVENT_MSG_RECEIVE);
Log.w(TAG, "User Received notification with Message: " + PushdataOpen.get("message"));
}
}
}
Main Activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Pushbots.sharedInstance().setCustomHandler(customHandler.class);
}
You need to add
Pushbots.sharedInstance().init(this);
in your activity's onCreate() method.

Push notification is not working using parse.com android?

I have created simple push notification app using parse.com.
devices registered successfully on parse.com but when i try to send push notification through parse.com no notification have come.
AndroidMainifest.xml Code:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission android:protectionLevel="signature"
android:name="com.parse.starter.permission.C2D_MESSAGE" />
<uses-permission android:name="com.parse.starter.permission.C2D_MESSAGE" />
service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.parse.starter" />
</intent-filter>
</receiver>
<meta-data
android:name="com.parse.APPLICATION_ID"
android:value="" />
<meta-data
android:name="com.parse.CLIENT_KEY"
android:value="" />
Reciever Code:
public class Receiver extends ParsePushBroadcastReceiver {
private Intent parseIntent;
public Receiver() {
super();
}
#Override
protected void onPushReceive(Context context, Intent intent) {
super.onPushReceive(context, intent);
if (intent == null)
return;
try {
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
parseIntent = intent;
} catch (JSONException e) {
Log.d("PushJsonException", "" + e.getMessage());
}
}
}
MainActivity Code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Parse.initialize(this);
ParseInstallation.getCurrentInstallation().saveInBackground();
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Call Methods to Update Your Stuff
}
};
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, new IntentFilter("com.example.harrypotter.pushnotificationdemo"));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
}
Application Class :
public class ParseApp extends Application {
#Override
public void onCreate() {
super.onCreate();
Parse.initialize(this);
ParseInstallation.getCurrentInstallation().saveInBackground();
}
}
You have not changed the Category attribute in your Manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<permission android:protectionLevel="signature"
android:name="com.parse.starter.permission.C2D_MESSAGE" />
<uses-permission android:name="com.parse.starter.permission.C2D_MESSAGE" />
service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
IMPORTANT: Change "com.parse.starter.permission.C2D_MESSAGE" in the lines below
to match your app's package name + ".permission.C2D_MESSAGE".
<receiver android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="YOUR PACKAGE NAME" />
</intent-filter>
</receiver>
<meta-data
android:name="com.parse.APPLICATION_ID"
android:value="" />
<meta-data
android:name="com.parse.CLIENT_KEY"
android:value="" />
Parse.com Hosted Service is fully retiring on January 28, 2017. If you have an existing application, refer to this link and create your own push notification server. Parse release a database migration tool that lets you migrate data from your Parse app to any MongoDB database.
For More Information Check The LInk

Android Parse Push Notifications Not Working - Outdated Device

I just updated the latest Parse SDK (1.11.0) and now I'm not receiving push notifications. I am able to register successfully and can see on the parse site that that my "developer" channel has been subscribed but pushes never get sent and I get this error:
PPNS - Outdated device - The records on this installation are
outdated, the user might have uninstalled the app.
Can someone please take a look at my code and see if you notice anything incorrect?
public class LSIApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Parse.initialize(this, "********", "********");
ParseInstallation.getCurrentInstallation().saveInBackground();
ParsePush.subscribeInBackground("developer", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.d("com.parse.push", "successfully subscribed to the broadcast channel.");
} else {
Log.e("com.parse.push", "failed to subscribe for push", e);
}
}
});
Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE);
}
}`
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="${applicationId}.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-permission android:name="${applicationId}.maps.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.telephony" android:required="false" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<permission android:protectionLevel="signature"
android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application android:name=".LSIApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="********" />
<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name=".startup.PushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
</application>
Note: The ${applicationId} is 'com.broker.schlisimobile.dev' and/or 'com.broker.schlisimobile' depending on whether it's a production or developer build.
Here is my custom PushBroadcastReceiver class:
public class PushBroadcastReceiver extends ParsePushBroadcastReceiver {
#Override
protected void onPushOpen(Context context, Intent intent) {
if ( storyJSONExists(intent) ) {
if (!DataController.getInstance().getCurrentUser().isGuestUser() ) {
Intent i = new Intent(context, PushLoadingActivity.class);
i.putExtras(intent.getExtras());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} else {
Intent i = new Intent(context, HomeActivity.class);
i.putExtra("promptForLogin", true);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(i);
}
} else {
Intent i = new Intent(context, HomeActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.putExtras(i);
context.startActivity(i);
}
}
private boolean storyJSONExists(Intent intent) {
try {
String jsonString = intent.getExtras().getString("com.parse.Data");
JSONObject json = new JSONObject(jsonString);
if ( json.has("postID") ) {
return true;
}
} catch (JSONException jsonE) {
jsonE.printStackTrace();
}
return false;
}
}
In your manifest.xml comment/delete below code,
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
then add below code in manifest.xml
<receiver
android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<!--IMPORTANT: Change "com.parse.starter" to match your app's package name.-->
<category android:name="your_application_id" />
</intent-filter>
</receiver>
hope it works.

Why my custom receiver is not working?

I use parse.com api.
What my problem is :
When other client send push notification I did not receive anything on my broadcastreceiver.
My manifest
<service android:name="com.parse.PushService" />
<receiver
android:name=".MainActivity$MyReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="com.yy.xx.UPDATE_STATUS" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
and my receiver in mainactivity is here:
public static class MyReceiver extends BroadcastReceiver {
public final String TAG = "MyReceiver";
#Override
public void onReceive(Context context, Intent intent) {
//this is not working,
try {
if (intent == null)
{
Log.d(TAG, "Receiver intent null");
}
else
{
String action = intent.getAction();
if (action.equals("com.yy.xx.UPDATE_STATUS"))
{
//....
}
}
} catch (JSONException e) {
Log.d(TAG, "JSONException: " + e.getMessage());
}
}
}
and my push notification send code is here:
JSONObject obj;
try {
obj =new JSONObject();
obj.put("action","com.yy.xx.UPDATE_STATUS");
obj.put("customdata","message...");
push_p = new ParsePush();
#SuppressWarnings("rawtypes")
ParseQuery query = ParseInstallation.getQuery();
// Notification for Android users
//query.whereEqualTo("deviceType", "android");
push_p.setQuery(query);
push_p.setData(obj);
push_p.setChannel("channel_111");
push_p.sendInBackground();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I read parse.com api and tutorial but I do not understand what is the problem.
thanks in advance
Add all this declarations in manifest
<!-- PARSE SERVICE AND RECEIVERS -->
<service
android:name="com.parse.PushService"
android:enabled="true" />
<receiver android:name="com.parse.ParseBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<receiver
android:name="com.parse.GcmBroadcastReceiver"
android:enabled="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.example.app" />
</intent-filter>
</receiver>
<receiver android:name=".MainActivity$MyReceiver" >
<intent-filter>
<action android:name="com.example.update.UPDATE_STATUS" />
</intent-filter>
</receiver>
And add permissions
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.example.app.permission.C2D_MESSAGE" />
<permission
android:name="com.example.app.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

Categories

Resources