All the logs print out are good, but the thing is not working. Please help.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abc.hcetest">
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".services.ApduService"
android:exported="true"
android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
<action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.nfc.cardemulation.host_apdu_service"
android:resource="#xml/apduservice" />
</service>
</application>
</manifest>
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String LOGTAG = MainActivity.class.toString();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread thread = new Thread(){
public void run(){
try{sleep(1000l);}catch(Exception e){}
setPreferredNFCService(true);
}
};
thread.start();
}
private void setPreferredNFCService(boolean isSet) {
Log.d(LOGTAG, "setPreferredNFCService isSet: " + isSet);
NfcAdapter nfc = NfcAdapter.getDefaultAdapter( this );
Log.d(LOGTAG, "(nfc != null): " + (nfc != null));
if ( nfc == null )
return; //HCEAppError.NFC_NOT_SUPPORT;
CardEmulation emulation = CardEmulation.getInstance(nfc);
if(emulation != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try{
if (isSet) {
ComponentName comp = new ComponentName(this, ApduService.class);
Log.d(LOGTAG, "(comp != null): " + (comp != null));
final boolean emulationRetVal = emulation.setPreferredService(this, comp);
Log.d(LOGTAG, "emulationRetVal: " + emulationRetVal);
} else {
emulation.unsetPreferredService(this);
}
}
catch(Exception e){
e.printStackTrace();
}
}
else{
Log.e(LOGTAG, "unsupported");
}
}
else{
Log.e(LOGTAG, "card emulation failed");
}
}
}
ApduService
public class ApduService extends HostApduService {
final static String LOGTAG = ApduService.class.getName();
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
if(commandApdu != null){
Log.d(LOGTAG, "processCommandApdu " + commandApdu.length);
}
else{
Log.d(LOGTAG, "processCommandApdu " + commandApdu);
}
return null;
}
private boolean canStartTrans() {
Log.d(LOGTAG, "in can start trans");
return true;
}
#Override
public void onDeactivated(int reason) {
Log.d(LOGTAG, "onDeactivated: " + reason);
}
}
The print out are:
setPreferredNFCService isSet: true
(nfc != null): true
(comp != null): true
emulationRetVal: true
Since the emulationRetVal is true, the ApduService is supposed to be active and tied to the CardEmulation thing. However, it does not work.
What must I do to get the HCE going?
You didn't show your apduservice.xml, which is the file in which the AID registrations happen. Alternatively, you should manually call CardEmulation::registerAidsForService from within your application.
Make sure you perform all the steps outlined in https://developer.android.com/guide/topics/connectivity/nfc/hce.html
Related
I'm using Phone Call states(CALL_STATE_OFFHOOK) and run my BroadcastReceiver class. it's working 5 or more calls(incoming/outgoing) after it stops the service. I don't know what went wrong here. if I want to run the service again, I want to open the app again. but this is not a broadcast service. and if I call an invalid number which is less than 10 numbers the broadcast services stops
Manifest
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity2"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <!-- This part is inside the application -->
<receiver
android:name=".CallReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
MyPhonestatreListener
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import java.util.Date;
public class MyPhoneStateListener extends PhoneStateListener {
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
public void onCallStateChanged(Context context, int state, String phoneNumber){
if(lastState == state){
//No change, debounce extras
return;
}
System.out.println("Number inside onCallStateChange : " + phoneNumber);
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
Toast.makeText(context, "Incoming Call Ringing " + phoneNumber, Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
Toast.makeText(context, "Outgoing Call Started " + phoneNumber, Toast.LENGTH_SHORT).show();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
//Went to idle- this is the end of a call. What type depends on previous state(s)
if(lastState == TelephonyManager.CALL_STATE_RINGING){
//Ring but no pickup- a miss
Toast.makeText(context, "Ringing but no pickup" + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();
}
else if(isIncoming){
Toast.makeText(context, "Incoming " + phoneNumber + " Call time " + callStartTime , Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "outgoing " + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();
}
break;
}
lastState = state;
}
}
CallReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;
public class CallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Log.w("intent " , intent.getAction().toString());
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener customPhoneListener = new MyPhoneStateListener();
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
Bundle bundle = intent.getExtras();
String phone_number = bundle.getString("incoming_number");
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
// String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
if (phone_number == null || "".equals(phone_number)) {
return;
}
customPhoneListener.onCallStateChanged(context, state, phone_number);
Toast.makeText(context, "Phone Number " + phone_number , Toast.LENGTH_SHORT).show();
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity {
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkAndRequestPermissions();
}
private boolean checkAndRequestPermissions() {
int readPhoneState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
int read_call_log = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG);
List listPermissionsNeeded = new ArrayList<>();
if (readPhoneState != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
}
if (read_call_log != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_CALL_LOG);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this,
listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),
REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
}
My call detector app is running fine on all android version except 8 Oreo. I get a deadlock paradigm: My detector is not called, and when I close the application the system kills it, not leaving it in the background.
I have already read the documentation from cable to tail https://developer.android.com/about/versions/oreo/background, I already looked a lot in google, and here in stack over flow, but no solution applied to my case, because of the required "dangerous" permissions.
My case seems simple: I have a detector, a service and the main with a button. I want it when the user calls a certain number, my main open.
What is the right way to fix this issue?
manifest.xml :
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service
android:name=".CallDetectionService"
android:enabled="true"
android:exported="false"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</activity>
</application>
CallDetectionService.java
public class CallDetectionService extends Service {
private CallDetector callDetector;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
callDetector = new CallDetector(this);
int r = super.onStartCommand(intent, flags, startId);
callDetector.start();
return r;
}
#Override
public void onDestroy() {
super.onDestroy();
callDetector.stop();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
CallDetector.java
public class CallDetector {
public static final String MY_PREF = "MY_PREF";
public static final String NUMBER_KEY = "NUMBER_KEY";
private SharedPreferences sharedPreferences;
public class OutgoingDetector extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
String compare_num = "12345678";
if (number.equals(compare_num)) {
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setResultData(null);
context.startActivity(i);
}
}
}
private Context ctx;
private OutgoingDetector outgoingDetector;
public CallDetector(Context ctx) {
this.ctx = ctx;
outgoingDetector = new OutgoingDetector();
}
public void start() {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
ctx.registerReceiver(outgoingDetector, intentFilter);
}
public void stop(){
ctx.unregisterReceiver(outgoingDetector);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private boolean detecting = false;
private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 0;
public boolean isPermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(android.Manifest.permission.CALL_PHONE)
== PackageManager.PERMISSION_GRANTED) {
Log.v("TAG", "Permission is granted");
return true;
} else {
Log.v("TAG", "Permission is revoked");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 1);
return false;
}
} else {
Log.v("TAG", "Permission is granted");
return true;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
button = (Button) findViewById(R.id.button);
/* button.setOnClickListener(this); */
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.CALL_PHONE)) {
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CALL_PHONE},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
}
}
String action = "START";
final Intent intent = new Intent(this, CallDetectionService.class);
intent.setAction(action);
startService(intent);
}
#Override
public void onResume() {
super.onResume();
SharedPreferences sharedPreferences = getSharedPreferences(CallDetector.MY_PREF, MODE_PRIVATE);
String number = sharedPreferences.getString(CallDetector.NUMBER_KEY, "URA VISUAL");
textView.setText(number);
}
}
What am I doing so wrong? I've been looking for a solution for 4 days and I still have not found anything.
I have and android wear and android phone app. I'm trying to get them connect and ultimately send messages from the watch to the phone. On the watch though, Wearable.CapabilityApi.getCapability() returns no nodes
Here is the Wear MainActivity:
public class MainActivity extends WearableActivity {
public static final String TAG = "WatchApp";
public GoogleApiClient mApiClient;
public static final int CONNECTION_TIME_OUT_MS = 1000;
public static String nodeId;
private static final String AIR_LIFT_CAPABILITY = "airlift";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initApi();
final Button btnUp = (Button)findViewById(R.id.btnUp);
btnUp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String text = "Preset";
//mAdapter.add( text );
//mAdapter.notifyDataSetChanged();
sendMessage( text );
Log.i("WatchApp", "btnUp Sent Preset");
}
});
Button btnDown = (Button)findViewById(R.id.btnDown);
btnDown.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String text = "AirOut";
//mAdapter.add( text );
//mAdapter.notifyDataSetChanged();
sendMessage(text );
Log.i("WatchApp", "btnUp Sent AirOut");
}
});
// Enables Always-on
setAmbientEnabled();
}
private void initApi() {
mApiClient = getGoogleApiClient(this);
setOrUpdateNotification();
Log.i("WatchApp", "initApi()");
}
private GoogleApiClient getGoogleApiClient(Context context) {
return new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.build();
}
private void setOrUpdateNotification() {
new Thread(new Runnable() {
#Override
public void run() {
CapabilityApi.GetCapabilityResult result =
Wearable.CapabilityApi.getCapability(
mApiClient, AIR_LIFT_CAPABILITY,
CapabilityApi.FILTER_REACHABLE).await(1000, TimeUnit.MILLISECONDS);
updateFindMeCapability(result.getCapability());
CapabilityApi.CapabilityListener capabilityListener =
new CapabilityApi.CapabilityListener() {
#Override
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
updateFindMeCapability(capabilityInfo);
}
};
// Wearable.CapabilityApi.addCapabilityListener(mApiClient, capabilityListener, AIR_LIFT_CAPABILITY);
}
}).start();
}
private void updateFindMeCapability(CapabilityInfo capabilityInfo) {
if (capabilityInfo.getNodes() == null) return;
Set<Node> connectedNodes = capabilityInfo.getNodes();
if (connectedNodes.isEmpty()) {
Log.i(TAG,"No Nodes Found.");
} else {
for (Node node : connectedNodes) {
// we are only considering those nodes that are directly connected
if (node.isNearby()) {
Log.i(TAG,"FOUND NODE");
nodeId = node.getId();
}
}
}
}
private void sendMessage(final String MESSAGE) {
if (nodeId != null) {
new Thread(new Runnable() {
#Override
public void run() {
mApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
Wearable.MessageApi.sendMessage(mApiClient, nodeId, MESSAGE, null);
mApiClient.disconnect();
Log.i("WatchApp", "Message ("+MESSAGE+") sent");
}
}).start();
} else {
Log.i("WatchApp", "No Nodes to send message!");
}
}
#Override
protected void onDestroy() {
super.onDestroy();
mApiClient.disconnect();
mApiClient = null;
Log.i("WatchApp", "onDestroy()");
}
}
Wear AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.schoen.jonathan.airliftwatch">
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#android:style/Theme.DeviceDefault">
<uses-library
android:name="com.google.android.wearable"
android:required="true" />
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name="com.schoen.jonathan.airliftwatch.MainActivity"
android:label="#string/app_name">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Phone MainActivity:
public class MainActivity extends Activity {
boolean mBound = false;
public static final String TAG = "PhoneApp";
public ListenerService listener;
public GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnStart = (Button)findViewById(R.id.btnStart);
Button btnStop = (Button)findViewById(R.id.btnStop);
Log.i("PhoneApp", "onCreate() Receiver Registered ");
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PhoneApp", "btnStart Receiver Registered");
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PhoneApp", "btnStop Receiver unRegistered");
}
});
registerListener();
}
public void registerListener() {
client = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.build();
listener = new ListenerService();
Wearable.MessageApi.addListener(client ,listener);
Log.i("PhoneApp", "registerListener() Listener Registered ");
}
#Override
protected void onStart() {
super.onStart();
registerListener();
Log.i("PhoneApp", "onStart() Listener Registered ");
}
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
registerListener();
Log.i("PhoneApp", "onResume() Listener Registered ");
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
//unregister our receiver
if (client != null && listener != null)
Wearable.MessageApi.removeListener(client, listener);
client = null;
listener = null;
Log.i("PhoneApp", "onPause() Listener Unregistered ");
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
//unregister our receiver
if (client != null && listener != null)
Wearable.MessageApi.removeListener(client, listener);
client = null;
listener = null;
Log.i("PhoneApp", "onPause() Listener Unregistered ");
}
}
Phone Listener Service:
public class ListenerService extends WearableListenerService {
String nodeId;
#Override
public void onMessageReceived(MessageEvent messageEvent) {
nodeId = messageEvent.getSourceNodeId();
Log.i(MainActivity.TAG, messageEvent.getPath());
showToast(messageEvent.getPath());
String msg_for_me = messageEvent.getPath();
if (msg_for_me == "AirOut")
{
Log.i(MainActivity.TAG, "Air Out");
} else if (msg_for_me == "Preset")
{
Log.i(MainActivity.TAG, "Preset");
}
}
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
Phone Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.schoen.jonathan.airliftwatch">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<service
android:name="com.schoen.jonathan.airliftwatch.ListenerService" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Phone wear.xml:
<resources>
<string-array name="android_wear_capabilities">
<item>airlift</item>
</string-array>
</resources>
Any ideas why I get null result for returned nodes? my phone and watch are currently paired and i get updates on my watch from my phone from things like facebook and emails.
As stated in this thread, NodeApi can be used on the device side.
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(mApiClient).await();
Then for each node within nodes, you can call getDisplayName().
Also, based from this link, use the same debug certificate for both the handheld and wearable app, otherwise the CapabilityAPI won't work.
I faced with the problem - Google map is not shown in my Android Application. The App is based on O'Reilly Android Task manager Application.
Here is my layout
<com.google.android.maps.MapView
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
class="com.google.android.gms.maps.MapFragment"
android:clickable="true"
android:apiKey="AIzaSyALl1yI4zMyjnHoTSkgQjKQLE78uWZcAYk"
android:layout_below="#id/map_location_button"
android:layout_above="#+id/use_this_location_button"/>
my Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.khalilov.android.taskmanager"
android:versionCode="1"
android:versionName="1.0" >
<permission
android:name="com.khalilov.android.taskmanager.permission.MAPS_RECEIVE"
android:protectionLevel="signature"></permission>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="true"
android:name=".TaskManagerApplication"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".ViewTasksActivity"
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=".AddTaskActivity" android:text="#string/app_name" />
<uses-library android:name="com.google.android.maps" />
<activity
android:name=".AddLocationMapActivity"
android:text="#string/add_location_to_task" />
<meta-data
android:name="com.google.android.v2.API_KEY"
android:value="AIzaSyALl1yI4zMyjnHoTSkgQjKQLE78uWZcAYk"/>
<service android:name=".services.MyService"/>
</application>
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="24" />
</manifest>
And Java code
public class AddLocationMapActivity extends MapActivity {
public static final String ADDRESS_RESULT = "address";
private EditText addressText;
private Button mapLocationButton;
private Button useLocationButton;
private MapView mapView;
private Address address;
private MyLocationOverlay myLocationOverlay;
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.add_location);
setUpView();
}
#Override
protected void onResume() {
super.onResume();
myLocationOverlay.enableMyLocation();
}
#Override
protected void onPause() {
super.onPause();
myLocationOverlay.disableMyLocation();
}
protected void mapCurrentAddress() {
//getting address from input
String addressString = addressText.getText().toString();
//geocoder - search for address to find a location
Geocoder g = new Geocoder(this);
List<Address> addresses;
try {
addresses = g.getFromLocationName(addressString, 1);
if(null != addresses && addresses.size()>0) {
address = addresses.get(0);
List<Overlay> mapOverlays = mapView.getOverlays();
AddressOverlay addressOverlay = new AddressOverlay(address);
mapOverlays.add(addressOverlay);
mapOverlays.add(myLocationOverlay);
mapView.invalidate();
final MapController mapController = mapView.getController();
mapController.animateTo(addressOverlay.getGeopoint(), new
Runnable() {
public void run() {
mapController.setZoom(12);
}
});
useLocationButton.setEnabled(true);
} else {
//Tell the user no results for that address
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void setUpView() {
addressText = (EditText)findViewById(R.id.task_address);
mapLocationButton = (Button)findViewById(R.id.map_location_button);
useLocationButton = (Button)findViewById(R.id.use_this_location_button);
mapView = (MapView)findViewById(R.id.map);
myLocationOverlay = new MyLocationOverlay(this, mapView);
mapView.getOverlays().add(myLocationOverlay);
mapView.invalidate();
useLocationButton.setEnabled(false);
mapView.setBuiltInZoomControls(true);
mapLocationButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mapCurrentAddress();
}
});
useLocationButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (null != address) {
Intent intent = new Intent();
intent.putExtra(ADDRESS_RESULT, address);
setResult(RESULT_OK, intent);
}finish();
}
});
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
#Override
//location of device
protected boolean isLocationDisplayed() {
return true;
}
}
log
It would be great if you help me to find the solution. Thanks
my server is sending the message to the gcm serer with a response code of 200. but my OnMessageReceiver is not getting called therefore im not getting the message.
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
private static int no_calls;
#Override
public void onMessageReceived (String from, Bundle data){
String message = data.getString("message");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
out.println("print something");
System.out.println("Message" + message + "from" + from);
sendNotification(message);
}
private void sendNotification(String message) {
System.out.println("Message" + message + "from");
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 = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_setting_dark)
.setContentTitle("GCM Message")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.caesar.gcm" >
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="21"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.example.caesar.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.caesar.gcm.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<reciever
android:name = "com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="com.example.caesar.gcm" />
</intent-filter>
</reciever>
<service
android:name=".MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<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>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
public class MainActivity extends Activity {
GoogleCloudMessaging gcm;
String regid;
TextView mDisplay;
TextView textView;
String SENDER_ID = "";
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
Context context;
AsyncHttpClient client = new AsyncHttpClient();
static final String TAG = "GCMDemo";
String mess = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDisplay = (TextView) findViewById(R.id.display);
textView = (TextView) findViewById(R.id.textView);
context = getApplicationContext();
// GCM registration.
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
textView.setText(regid);
SendID();
if (regid.isEmpty()) {
registerInBackground();
}
} else {
Log.i(TAG, "No valid Google Play Services APK found.");
}
}
public void SendID(){
final RequestParams params = new RequestParams();
params.put("id", regid);
client.post("", params, new JsonHttpResponseHandler() {
#Override
public void onStart() {
// called before request is started
}
public void onSuccess(int statusCode, PreferenceActivity.Header[] headers, JSONObject response) {
}
public void onFailure(int statusCode, PreferenceActivity.Header[] headers, JSONObject errorResponse, Throwable e) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// called when request is retried
}
});
}
private boolean checkPlayServices() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (status != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(status)) {
Log.i(TAG, String.valueOf(status));
} else {
Toast.makeText(this, "This device is not supported.",
Toast.LENGTH_LONG).show();
finish();
}
return false;
}
return true;
}
private void registerInBackground() {
new AsyncTask<Void,Void,String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
// You should send the registration ID to your server over HTTP,
// so it can use GCM/HTTP or CCS to send messages to your app.
// The request to your server should be authenticated if your app
// is using accounts.
sendRegistrationIdToBackend();
// For this demo: we don't need to send it because the device
// will send upstream messages to a server that echo back the
// message using the 'from' address in the message.
// Persist the registration ID - no need to register again.
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
// If there is an error, don't just keep trying to register.
// Require the user to click a button again, or perform
// exponential back-off.
}
return msg;
}
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getGCMPreferences(context);
int appVersion = getAppVersion(context);
Log.i(TAG, "Saving regId on app version " + appVersion);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
#Override
protected void onPostExecute(String msg) {
mDisplay.append(msg + "\n");
}
}.execute(null, null, null);
}
private void sendRegistrationIdToBackend() {
// Your implementation here.
}
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
Log.i(TAG, "Registration not found.");
return "";
}
// Check if app was updated; if so, it must clear the registration ID
// since the existing registration ID is not guaranteed to work with
// the new app version.
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
Log.i(TAG, "App version changed.");
return "";
}
return registrationId;
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
private SharedPreferences getGCMPreferences(Context context) {
// This sample app persists the registration ID in shared preferences, but
// how you store the registration ID in your app is up to you.
return getSharedPreferences(Activity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
}
//updated main
public class MainActivity extends Activity {
GoogleCloudMessaging gcm;
TextView mDisplay;
TextView textView;
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
Context context;
AsyncHttpClient client = new AsyncHttpClient();
static final String TAG = "GCMDemo";
Context mContext = this;
String mess = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDisplay = (TextView) findViewById(R.id.display);
textView = (TextView) findViewById(R.id.textView);
SharedPreferences appPrefs = mContext.getSharedPreferences("com.example.caesar.gcm", Context.MODE_PRIVATE);
String token = appPrefs.getString("token", "");
if (token.isEmpty()) {
try {
getGCMToken("1048700326431");// Project ID: xxxx Project Number: 0123456789 at https://console.developers.google.com/project/...
textView.setText(token);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private void getGCMToken(final String senderId) throws Exception {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
String token = "";
try {
InstanceID instanceID = InstanceID.getInstance(mContext);
token = instanceID.getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
if (token != null && !token.isEmpty()) {
SharedPreferences appPrefs = mContext.getSharedPreferences("com.example.caesar.gcm", Context.MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = appPrefs.edit();
prefsEditor.putString("token", token);
prefsEditor.apply();
}
Log.i("GCM_Token", token);
textView.setText(token);
SendID(token);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
public void SendID(String token){
final RequestParams params = new RequestParams();
params.put("id", token);
client.post("https://death-sarodh.c9.io/gcm", params, new JsonHttpResponseHandler() {
#Override
public void onStart() {
// called before request is started
}
public void onSuccess(int statusCode, PreferenceActivity.Header[] headers, JSONObject response) {
}
public void onFailure(int statusCode, PreferenceActivity.Header[] headers, JSONObject errorResponse, Throwable e) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
}
#Override
public void onRetry(int retryNo) {
// called when request is retried
}
});
}
}
Replace reciever in your Manifest by receiver.
Moreover, make sure your app successfully got the token (registration device Id). Hope this helps!
My Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gcmclient" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.gcm" />
</intent-filter>
</receiver>
<service android:name=".service.GcmService" android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service android:name=".service.LoggingService" android:exported="false" />
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:clearTaskOnLaunch="false"
android:finishOnTaskLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Moreover, check your sever-side response after sending. Perhaps you will get response message like the following if GCM message sucessfully sent:
{"multicast_id":6371085842931382567,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1240780242421810%4c427ca6f9fd7ecd"}]}
About getting token, firstly, I check SharedPreferences, if empty, get token (device registration id) from Google server. Token will be stored in SharedPreferences for other use / providing to server-side app.
public class MainActivity extends Activity {
Context mContext = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
SharedPreferences appPrefs = mContext.getSharedPreferences("com.example.gcmclient_preferences", Context.MODE_PRIVATE);
String token = appPrefs.getString("token", "");
if (token.isEmpty()) {
try {
getGCMToken("0123456789"); // Project ID: xxxx Project Number: 0123456789 at https://console.developers.google.com/project/...
} catch (Exception ex) {
ex.printStackTrace();
}
}
...
}
...
private void getGCMToken(final String senderId) throws Exception {
new AsyncTask<Void, Void, Void>() {
#Override
protected String doInBackground(Void... params) {
String token = "";
try {
InstanceID instanceID = InstanceID.getInstance(mContext);
token = instanceID.getToken(senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
if (token != null && !token.isEmpty()) {
SharedPreferences appPrefs = mContext.getSharedPreferences("com.example.gcmclient_preferences", Context.MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = appPrefs.edit();
prefsEditor.putString("token", token);
prefsEditor.commit();
}
Log.i("GCM_Token", token);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
}
Change this line
android:name=".MyGcmListenerService"
instead of above line
android:name="your package.MyGcmListenerService"
example com.yourappname.gcm.GcmIntentService
<service
android:name=".MyGcmListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
simple example code for BroadCastReceiver.
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
IntentService
public class GcmIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundles
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
if (GoogleCloudMessaging.
MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server: " +
extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
Log.e(":::gcm message",extras.getString("key");
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}
Remove below line from your manifest
<permission android:name="com.example.caesar.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
Manifest
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission
android:name="com.example.gcm.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />
<receiver
android:name="com.yourappname.gcm.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.example.gcm" />
</intent-filter>
</receiver>
<service android:name="com.yourappname.gcm.GcmIntentService" />