I'm trying to block incoming call in android. I have this BroadcastReceiver but it handles the incoming call but does not block incoming call on my android 2.3.6 phone(didn't try on other versions).
here is my receiver:
public class PhoneCallReceiver extends BroadcastReceiver {
Context context = null;
private static final String TAG = "Phone call";
private ITelephony telephonyService;
#Override
public void onReceive(Context context, Intent intent) {
Log.v(TAG, "Receving....");
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
try {
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
// telephonyService.silenceRinger();
telephonyService.endCall();
} catch (Exception e) {
Log.v(TAG, "failed....");
e.printStackTrace();
}
}
}
and the ITelephony
package com.callblocker.mk;
interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
call this method in Broadcast Receiver
public static void disconnectPhoneItelephony(Context context) {
ITelephony telephonyService;
Log.v(TAG, "Now disconnecting using ITelephony....");
TelephonyManager telephony = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Log.v(TAG, "Get getTeleService...");
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
telephonyService.endCall();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG,
"FATAL ERROR: could not connect to telephony subsystem");
Log.e(TAG, "Exception object: " + e);
}
}
//Broadcast Receiver
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals("android.intent.action.PHONE_STATE"))
return;
else {
disconnectPhoneItelephony(context);
}}
//Manifest
<!-- BLOCK CALL -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_INCOMING_CALLS" />
<receiver android:name="receiver.CallReceiver" >
<intent-filter android:priority="999" >
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Related
I want to create programm for autochanging network mode. I'm already read same topics and parically found parts of code, but I have little problem.
Boolean success = (Boolean) setPreferredNetwork.invoke(mTelephonyManager,
networkType);
In this part of code, I don't know how to define "mTelephonyManager", can someone help me with this? Almost full code below.
MainActivity
package com.example.a4genforce;
import * *
public class MainActivity extends Activity {
int networkType = 12; //LTE/WCDMA
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setPreferredNetwork(networkType);
}
public Method getHiddenMethod(String methodName, Class fromClass, Class[] params) {
Method method = null;
try {
Class clazz = Class.forName(fromClass.getName());
method = clazz.getMethod(methodName, params);
method.setAccessible(true);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return method;
}
public void setPreferredNetwork(int networkType) {
try {
Method setPreferredNetwork = getHiddenMethod("setPreferredNetworkType",
TelephonyManager.class, new Class[]{int.class});
Boolean success = (Boolean) setPreferredNetwork.invoke(mTelephonyManager,
networkType);
Log.i(TAG, "Could set Network Type ::: " + (success.booleanValue() ? "YES" : "NO"));
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void onMyClick(View view) {
Toast.makeText(this, "Зачем вы нажали?", Toast.LENGTH_SHORT).show();
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("com.android.settings", "com.android.settings.RadioInfo");
startActivity(intent);
} catch (Exception e) {
Toast.makeText(getApplicationContext(), " Device not supported", Toast.LENGTH_LONG).show();
}
}
}
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.a4genforce">
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" tools:ignore="ProtectedPermissions"/>
<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"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
I need to end the call after the ring has been made (kind of like a missed call). I used BroadcastReceiver and PhoneStateListener to monitor the states.
The problem is I'm receiving a broadcast and also the phonenumber, and the listener works well - it goes inside the switch and executes the case intended, but it doesn't execute the endCall method of the ITelephony interface. Here's my code:
Manifest:
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<receiver
android:name=".EndCall"
android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
EndCall.java
public class EndCall extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Debug", "Received a broadcast...");
String phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("Debug", "Phone number: " + phonenumber);
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
EndCallListener callListener = new EndCallListener(context, tm);
tm.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
EndCallListener.java:
public class EndCallListener extends PhoneStateListener {
Context context;
TelephonyManager tm;
public EndCallListener(Context context, TelephonyManager tm) {
this.context = context;
this.tm = tm;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i("Debug", "OFFHOOK");
try {
Log.i("Debug", "Inside try...");
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
ITelephony telephonyService = (ITelephony) m.invoke(tm);
//nothing happens after this...
if(telephonyService.endCall()) {
Log.i("Debug", "Call ended...");
} else {
Log.i("Debug", "Call not ended...");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.i("Debug", "IDLE");
break;
}
}
}
ITelephony.aidl
package com.android.internal.telephony;
interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
The last comment makes things unclear (In the question post).. "It do end the call, but the problem is I want to end the call when it is ringing or some time after the call has been attended."
So the call is ended but you want it to end while ringing or after some time ?
2 cases here:
- While ringing: You need to check for CALL_STATE_RINGING and then go over to How to reject a call programatically android and check the techniques there
Some time after the call has been made: just call the method endCall() at a later stage from a Runnable (Or a different mechanism), you just postDelayed() on a handler and set some kind of delay time.
In the code that runs in the Runnable I would check that the call is still ongoing
I'm probably off-mark, I suggest you clarify your comment/question
You are monitoring only for outgoing calls in your manifest. You can also monitor for phone state as well in manifest receiver.
Basically you want to end an outgoing call after few (e.g. 10) seconds of ringing or getting picked.
THERE IS NOT ANY WAY TO KNOW WHETHER AN OUTGOING CALL IS ANSWERED OR STILL RINGING since android does not send any update on this.
But since, you need to end an outgoing call only after few seconds your EndCallListener code should be like this:-
public class EndCallListener extends PhoneStateListener {
Context context;
TelephonyManager tm;
public EndCallListener(Context context, TelephonyManager tm) {
this.context = context;
this.tm = tm;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.i("Debug", "OFFHOOK");
try {
Log.i("Debug", "Inside try...");
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
ITelephony telephonyService = (ITelephony) m.invoke(tm);
//nothing happens after this...
if(telephonyService.endCall()) {
Log.i("Debug", "Call ended...");
} else {
Log.i("Debug", "Call not ended...");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}, 10000);
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.i("Debug", "IDLE");
break;
}
}
}
You can only detect when the phone starts to make an outgoing call and when the outgoing call is hunged up but you can't determine when a "ringing" is started.
The only workaround is to hang up after the outgoing call starts and passes for some seconds, but then, you're never guaranteed the phone will start ringing:
public class EndCallListener extends PhoneStateListener {
int lastState = TelephonyManager.CALL_STATE_IDLE;
boolean isIncoming;
//Incoming call- IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when hung up
//Outgoing call- from IDLE to OFFHOOK when dialed out, to IDLE when hunged up
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
if(lastState == state){
//No change
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
//incoming call started
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//Transition of ringing->offhook are pickups of incoming calls. Nothing down on them
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
//outgoing call started
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Log.i("Debug", "OFFHOOK");
try {
Log.i("Debug", "Inside try...");
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
ITelephony telephonyService = (ITelephony) m.invoke(tm);
//nothing happens after this...
if(telephonyService.endCall()) {
Log.i("Debug", "Call ended...");
} else {
Log.i("Debug", "Call not ended...");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}, 10000);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
//End of call(Idle). The type depends on the previous state(s)
if(lastState == TelephonyManager.CALL_STATE_RINGING){
// missed call
}
else if(isIncoming){
//incoming call ended
}
else{
//outgoing call ended
}
break;
}
lastState = state;
}
}
}
Objective: send a ping to android clients. I have an array of device registration Id's held in my user object.
In GCMIntentService.java, auto created within my app, I get that registration id here
/**
* Called back when a registration token has been received from the Google
* Cloud Messaging service.
*
* #param context
* the Context
*/
#Override
public void onRegistered(Context context, String registration) {
Log.d(TAG, "onRegistered(context, registration), Registration: " + registration);
and then create the DeviceInfo object (also pre defined with app engine) and then add this ID to the user through another endpoint. I have confirmed this works/ see the string held and assume that my device is now registered properly.
When certain things happen in the backend, I have a custom notification class and run this method:
public void sendNotificationPingToUsers(
#Named("userIds") ArrayList<Long> userIds,
ZeppaNotification notification) throws IOException {
Sender sender = new Sender(Constants.SENDER_ID);
PersistenceManager mgr = getPersistenceManager();
try {
ArrayList<String> allDevices = new ArrayList<String>();
for (int i = 0; i < userIds.size(); i++) {
long userId = userIds.get(i);
ZeppaUser zeppaUser = mgr
.getObjectById(ZeppaUser.class, userId);
if (zeppaUser != null) {
ZeppaNotification specificNotification = new ZeppaNotification();
specificNotification.setToUserId(userId);
specificNotification.setFromUserId(notification
.getFromUserId());
specificNotification.setEventId(notification.getEventId());
specificNotification.setExtraMessage(notification
.getExtraMessage());
specificNotification.setNotificationType(notification
.getType());
String extraMessage = specificNotification
.getExtraMessage();
if (extraMessage.length() > 1000) {
extraMessage = extraMessage.substring(0, 1000)
+ "[...]";
}
mgr.makePersistent(specificNotification);
allDevices.addAll(zeppaUser.getDevices());
}
}
if (!allDevices.isEmpty()) {
Message msg = new Message.Builder().collapseKey("sendToSync")
.build();
MulticastResult result = sender.send(msg, allDevices, 5);
result.getTotal();
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
mgr.close();
}
}
I pass in the other notification so I can recreate it for all users, hold it in the notification table, then ping the device so that it can pull this and any others unseen and create a status bar notification.
This method, again in GCMIntentService:
#Override
public void onMessage(Context context, Intent intent) {
Log.d(TAG, "received message ping");
Is never called and this is where I am trying to handle everything from the device side of things. Can anyone point out what I may be doing wrong or if I am incorrectly interpreting the way this service works?
Thank you
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<permission
android:name="com.minook.zeppa.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.minook.zeppa.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:name=".ZeppaApplication"
android:allowBackup="true"
android:icon="#drawable/zeppa_icon"
android:label="#string/app_name"
android:testOnly="false"
android:theme="#style/ZeppaTheme"
android:uiOptions="none" >
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<activity
android:name=".LoginActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".CreateAccountActivity"
android:label="#string/create_account"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".NewFriendsActivity"
android:label="#string/add_friends"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
</activity>
<activity
android:name=".EventViewActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".NewEventActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".UserActivity"
android:label="#string/app_name"
android:logo="#drawable/zeppa_icon" >
</activity>
<activity
android:name=".ZeppaPreferenceActivity"
android:label="#string/event_details"
android:logo="#drawable/zeppa_icon" >
</activity>
<!--
<activity
android:name=".RegisterActivity"
android:launchMode="singleTop" >
</activity>
-->
<service android:name=".GCMIntentService" />
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.minook.zeppa" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.minook.zeppa" />
</intent-filter>
</receiver>
</application>
Another Note: i have tried using the project number and a server key generated by the GAE console with no specified IP. Neither have worked so far.
I just realized I never came back to this.
Turns out that he app-engine created GCM code isn't the ideal way to do it. This is is the essential code in my application with now successfully sends a send-to-sync from the backend and displays a notification in the status bar.
public class ZeppaGCMReceiver extends WakefulBroadcastReceiver {
final private static String TAG = "GCMIntentService";
private static String registrationId = null;
public static void register(final ZeppaApplication application) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
.getApplicationContext());
try {
registrationId = gcm.register(Constants.PROJECT_NUMBER);
Log.d(TAG, "gcm.register( " + registrationId + " )");
ZeppaUser currentUser = ZeppaUserSingleton.getInstance().getUser();
if (currentUser.getDevices() == null
|| !currentUser.getDevices().contains(registrationId)) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Zeppauserendpoint.Builder endpointBuilder = new Zeppauserendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(),
application.getGoogleAccountCredential());
endpointBuilder = CloudEndpointUtils
.updateBuilder(endpointBuilder);
Zeppauserendpoint userEndpoint = endpointBuilder
.build();
try {
RegisterUserDevice registerTask = userEndpoint
.registerUserDevice(
ZeppaUserSingleton.getInstance().getUserId(),
registrationId);
registerTask.execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}.execute();
} else {
Log.d(TAG, "Already Registered");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void unregister(final ZeppaApplication application) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
.getApplicationContext());
// TODO: registration id in preferences and
try {
gcm.unregister();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "received message ping");
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String messageType = gcm.getMessageType(intent);
Log.d(TAG, "MessageType: " + messageType);
if (messageType == null) {
Log.d(TAG, "Message is null");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
.equals(messageType)) {
Log.d(TAG, "Error!");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
.equals(messageType)) {
Log.d(TAG, "Deleted");
return;
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
.equals(messageType)) {
Log.d(TAG, "Message");
handlePingInAsync(context);
} else {
Log.d(TAG, "WTF are you..? " + intent.toString());
}
}
private void handlePingInAsync(Context context) {
Context[] param = {context};
new AsyncTask<Context, Void, Void>() {
#Override
protected Void doInBackground(Context... params) {
Context context = params[0];
GoogleAccountCredential credential = getCredential(context);
if (credential == null) {
return null;
}
Zeppanotificationendpoint.Builder endpointBuilder = new Zeppanotificationendpoint.Builder(
AndroidHttp.newCompatibleTransport(),
new JacksonFactory(), credential);
endpointBuilder = CloudEndpointUtils
.updateBuilder(endpointBuilder);
Zeppanotificationendpoint notificationEndpoint = endpointBuilder
.build();
try {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SHARED_PREFS, Context.MODE_PRIVATE);
Long userId = prefs.getLong(Constants.USER_ID, -1);
if (userId > 0) {
GetUnseenNotifications getUnseenNotifications = notificationEndpoint
.getUnseenNotifications(userId);
CollectionResponseZeppaNotification collectionResponse = getUnseenNotifications
.execute();
if (collectionResponse == null
|| collectionResponse.getItems() == null) {
} else {
List<ZeppaNotification> notifications = collectionResponse
.getItems();
sendNotificationsForResult(notifications,
context);
try {
NotificationSingleton.getInstance()
.addAllNotifcations(notifications);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
} else {
Log.d(TAG, "No Set userId");
}
} catch (IOException ioEx) {
ioEx.printStackTrace();
}
return null;
}
}.execute(param);
}
private GoogleAccountCredential getCredential(Context context) {
GoogleAccountCredential credential = ((ZeppaApplication) context.getApplicationContext())
.getGoogleAccountCredential();
if (credential == null) {
SharedPreferences prefs = context.getSharedPreferences(
Constants.SHARED_PREFS, Context.MODE_PRIVATE);
String email = prefs.getString(Constants.EMAIL_ADDRESS, null);
if (email != null && !email.isEmpty() && Constants.IS_CONNECTED) {
credential = GoogleAccountCredential.usingAudience(context,
Constants.APP_ENGINE_AUDIENCE_CODE);
credential.setSelectedAccountName(email);
return credential;
}
return null;
} else {
return credential;
}
}
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
private void sendNotificationsForResult(List<ZeppaNotification> resultList,
Context context) {
Log.d(TAG, "trying to send Notifications for result");
Notification.Builder notifBuilder = new Notification.Builder(context);
if (resultList.size() > 1) {
notifBuilder.setContentTitle(resultList.size()
+ " new notifications");
StringBuilder stringBuilder = new StringBuilder();
for (ZeppaNotification notification : resultList) {
stringBuilder.append(notification.getExtraMessage()).append(
'\n');
}
notifBuilder.setContentText(stringBuilder.toString());
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, true);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
notifBuilder.setContentIntent(pendingIntent);
} else {
ZeppaNotification notification = resultList.get(0);
manageSingleNotification(context, notification, notifBuilder);
notifBuilder.setContentText(notification.getExtraMessage());
}
notifBuilder.setLights(Color.CYAN, 750, 3000);
notifBuilder.setAutoCancel(true);
notifBuilder.setSmallIcon(R.drawable.notif_ic_zeppa);
Notification notification = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
notifBuilder.setPriority(Notification.PRIORITY_DEFAULT);
notification = notifBuilder.build();
} else {
notification = notifBuilder.getNotification();
}
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Log.d(TAG, "Notification Should Post");
notificationManager.notify(0, notification);
}
private void manageSingleNotification(Context context,
ZeppaNotification notification, Notification.Builder builder) {
Intent intent = null;
switch (notification.getNotificationOrdinal()) {
case 0:
builder.setContentTitle("New Friend Request");
intent = new Intent(context, NewFriendsActivity.class);
break;
case 1:
builder.setContentTitle("New Connection");
intent = new Intent(context, UserActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_USER_ID,
notification.getFromUserId());
break;
case 2:
builder.setContentTitle("Event Recommendation");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 3:
builder.setContentTitle("New Invite");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 4:
builder.setContentTitle("Event Comment");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 5:
builder.setContentTitle("Event Canceled");
intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
break;
case 6:
builder.setContentTitle("Event Updated");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 7:
builder.setContentTitle("Friend Joined Event");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 8:
builder.setContentTitle("Friend Left Event");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
case 9:
builder.setContentTitle("Let's Find a Time?");
break;
case 10:
builder.setContentTitle("Time Found!");
break;
case 11:
builder.setContentTitle("Event Reposted");
intent = new Intent(context, EventViewActivity.class);
intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
notification.getEventId());
break;
default: // this shouldnt happen
builder.setContentTitle("New Zeppa Notification");
intent = new Intent(context, MainActivity.class);
intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
break;
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
builder.setContentIntent(pendingIntent);
}
}
And then my Manifest needed:
<permission
android:name="package.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="package.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<receiver
android:name="package.ZeppaGCMReceiver"
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="package.GCMIntentService" />
</intent-filter>
</receiver>
<service
android:name="package.ZeppaGCMService"
android:enabled="true" />
Then, finally, from my endpoints class, when certain things were entered into the database, I determined which users should be notified, and fired this method:
NOTE: getDevices only returns the android device IDS. I got rid of the DeviceInfo class, it didn't seem useful but that should be the improper way of handling this. iOS is handled differently as I am sure you are aware. Will update if I change this/ if people want to see the iOS implementation.
public void sendNotificationPingToUsers(
#Named("userIds") List<Long> userIds,
ZeppaNotification notification) {
Sender sender = new Sender(Constants.SENDER_ID);
PersistenceManager mgr = getPersistenceManager();
try {
List<String> allDevices = new ArrayList<String>();
for (int i = 0; i < userIds.size(); i++) {
long userId = userIds.get(i);
ZeppaUser zeppaUser = mgr
.getObjectById(ZeppaUser.class, userId);
if (zeppaUser != null) {
ZeppaNotification specificNotification = new ZeppaNotification();
specificNotification.setToUserId(userId);
specificNotification.setFromUserId(notification
.getFromUserId());
specificNotification.setEventId(notification.getEventId());
specificNotification.setExtraMessage(notification
.getExtraMessage());
specificNotification.setNotificationType(notification
.getType());
mgr.makePersistent(specificNotification);
allDevices.addAll(zeppaUser.getDevices());
}
}
if (!allDevices.isEmpty()) {
Message msg = new Message.Builder().collapseKey("sendToSync")
.build();
MulticastResult result = sender.send(msg, allDevices, 500);
result.getTotal();
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
mgr.close();
}
}
What I want and do:
I get a bluetooth connection to a paired device when starting the app using Asynctask. --> new ConnectTask().execute("AMVCarsharingKit");
This works perfect for the first connection.
Then I have an TimerTask with a Timer which "looks" if a message from the other device was send. If a right message was send the appropriate if will be executed.
This also works fine when the first connection is running.
Now to the important point. I have a BroadcastReceiver for watching the device if it's charging or not. I have this in my manifest:
<receiver android:name=".ChargingOnReceiver" android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
</intent-filter>
</receiver>
<receiver android:name=".NotChargingOnReceiver" android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
This also works fine.
When it's not charging anymore I disable the bluetooth and close the socket (Look code below). Works fine.
When it's charging again I enable the bluetooth again and start the Activity where the main part will be done. In this Activity I have to reconnect to the other device again (Look at oncreat below). This reconnection works also ( it seems so).
I also receive the messages from the other device without problems. But the Timertask with the many if-terms which looks permanantly for received messages makes problems when the second connection with the other bluetooth device runs.
I receive the messages correctly and the right if-clause is executed, but most time it doesn't do the commands which are in the if-clause. For example it doesn't go in the right view of the viewflipper. Except the "Call if-clause", this works perfectly all the time.
I really have no idea why this is happening or rather this is not happening.
Has anyone an idea what could be wrong or influence the code?
BroadcastReceiver when device is NOT charging (snipped code):
Context applicationContext = CheckVehicleActivity
.getContextOfApplication();
//Disable bluetooth
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
MyApplication app = (MyApplication) applicationContext;
app.setIsCharging(false);
mmSocket = app.getmSocket();
try {
mmSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BroadcastReceiver when device i charging again (snipped code):
Context applicationContext = CheckVehicleActivity
.getContextOfApplication();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable();
MyApplication app = (MyApplication) applicationContext;
app.setIsCharging(true);
Intent i = new Intent(context, CheckVehicleActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
onCreate (snipped code):
// executed when it's charging again
Boolean isCharging = app.getIsCharging();
if(isCharging == true){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
MyApplication app = (MyApplication) getApplicationContext();
new ConnectTask().execute("AMVCarsharingKit");
app.setIsCharging(false);
}
}, 3000);
}else{
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
MyApplication app = (MyApplication) getApplicationContext();
new ConnectTask().execute("AMVCarsharingKit");
app.setIsCharging(false);
}
}, 3000);
}
// Cyclic reading of incoming messages
TimerTask task = new TimerTask() {
#Override
public void run() {
pHandler.post(new Runnable() {
#Override
public void run() {
try {
new ReadTask().execute();
MyApplication app = (MyApplication) getApplicationContext();
app.setReceivedMsg(receivedMsg);
if (receivedMsg.contains(HANDY_ON)) {
int id = viewFlipper.getDisplayedChild();
if (id == 0) {
showSoftKeyboard();
}
pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
wakeLock.acquire();
BrightnessUp();
receivedMsg = null;
}
if (receivedMsg.contains(HANDY_OFF)) {
// Go to login screen
viewFlipper.setDisplayedChild(0);
BrightnessDown();
if (wakeLock.isHeld())
wakeLock.release();
receivedMsg = null;
}
if (receivedMsg.contains(KEY_OUT)) {
viewFlipper.setDisplayedChild(4);
driveModus = true;
counterDrive = true;
startCounter();
receivedMsg = null;
}
if (receivedMsg.contains(CALL_ON)) {
vfID = viewFlipper.getDisplayedChild();
app.setVfId(vfID);
// Register the intent for phone call
Intent callIntent = new Intent(
Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:12345678"));
app.setPhone(1);
startActivityForResult(callIntent, 1);
receivedMsg = null;
}
if (receivedMsg.contains(FUELCARD_OUT)) {
int vfIDf = viewFlipper.getDisplayedChild();
app.setVfId(vfIDf);
if(vfIDf == 0){
hideSoftKeyboard();
}
if (driveModus == true) {
// Parse the tank PIN
int start = receivedMsg.indexOf(".") + 1;
int end = receivedMsg.length() - start;
tankPIN = String.copyValueOf(
receivedMsg.toCharArray(), start,
end);
txtTankID.setText(tankPIN);
viewFlipper.setDisplayedChild(5);
countDownTimer.start();
handler();
} else if (endModus == true) {
fuelNotAllowed
.setText("You already finished your booking. Please put the fuelcard back to the box.");
viewFlipper.setDisplayedChild(9);
} else {
viewFlipper.setDisplayedChild(9);
}
receivedMsg = null;
}
if (receivedMsg.contains(FUELCARD_IN)) {
int id = app.getVfId();
viewFlipper.setDisplayedChild(id);
if(id==0){
showSoftKeyboard();
}
BrightnessUp();
receivedMsg = null;
}
if (receivedMsg.contains(KEY_IN)) {
viewFlipper.setDisplayedChild(7);
System.out.println("KeyIn-Check: " + receivedMsg);
receivedMsg = null;
}
} catch (Exception e) {
System.out.println("Async-Check: " + receivedMsg);
System.out.println(e);
}
}
});
}
};
timer.schedule(task, 0, 1000);
AsyncTask for the bluetooth connection:
// Get bluetooth connection to the device
private class ConnectTask extends
AsyncTask<String, String, BluetoothSocket> {
BluetoothDevice mmDevice;
Set<BluetoothDevice> mBluetoothAdapter;
#Override
protected BluetoothSocket doInBackground(String... params) {
try {
MyApplication app = (MyApplication) getApplicationContext();
bAdapter = BluetoothAdapter
.getDefaultAdapter();
// Get the all devices which are bonded
mBluetoothAdapter = bAdapter.getBondedDevices();
for (BluetoothDevice bc : mBluetoothAdapter) {
if (bc.getName().indexOf("AMVCarsharingKit") != -1) {
UUID uuid = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"); // Standard
// SerialPortService
// ID
mmDevice = bc;
mmSocket = mmDevice
.createInsecureRfcommSocketToServiceRecord(uuid);
mmSocket.connect();
BufferedWriter Writer = new BufferedWriter(
new OutputStreamWriter(
mmSocket.getOutputStream()));
Writer.write(BLUETOOTH_CONNECTED);
Writer.flush();
app.setmSocket(mmSocket);
break;
}
}
return mmSocket;
} catch(IOException e){
bAdapter.cancelDiscovery();
}
catch (Exception ex) {
System.out.println(ex);
}
return null;
}
}
AsyncTask for reading from the device which is connected:
// Read messages which are send from the connected device
private static class ReadTask extends
AsyncTask<String, String, BluetoothSocket> {
#Override
protected BluetoothSocket doInBackground(String... params) {
try {
System.out.println("Test: Before Reader");
BufferedReader Reader = new BufferedReader(
new InputStreamReader(mmSocket.getInputStream()));
receivedMsg = Reader.readLine();
System.out.println("Reader: " + receivedMsg);
} catch (Exception ex) {
System.out.println(ex);
}
return null;
}
protected void onPostExecute(BluetoothSocket result) {
}
}
I am using oauth-signpost as my OAuth library. When I direct the user to the authorization page, the user logs in and can authorize my application. When that happens, the application is returned to focus and starts the onCreate() method instead of the onResume() method.
My code as follows:
private static final String CONSUMER_KEY = "---";
private static final String CONSUMER_SECRET = "---";
private static String ACCESS_KEY = null;
private static String ACCESS_SECRET = null;
private static final String REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token";
private static final String ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token";
private static final String AUTH_URL = "https://api.twitter.com/oauth/authorize";
private static final String CALLBACK_URL = "myApp://Tweets";
private static CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY,CONSUMER_SECRET);
private static CommonsHttpOAuthProvider provider = new CommonsHttpOAuthProvider(REQUEST_TOKEN_URL,ACCESS_TOKEN_URL,AUTH_URL);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String authUrl = null;
try {
authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
} catch(OAuthMessageSignerException e) {
e.printStackTrace();
} catch(OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch(OAuthExpectationFailedException e) {
e.printStackTrace();
} catch(OAuthCommunicationException e) {
e.printStackTrace();
}
Log.d("OAuthTwitter", "authUrl" + authUrl);
WebView webview = new WebView(this);
webview.getSettings().setJavaScriptEnabled(true);
webview.setVisibility(View.VISIBLE);
setContentView(webview);
webview.loadUrl(authUrl);
}
#Override
public void onResume() {
super.onResume();
Uri uri = this.getIntent().getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
Log.d("OAuthTwitter", uri.toString());
String verifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
Log.d("OAuthTwitter", verifier);
try {
provider.retrieveAccessToken(consumer, verifier);
ACCESS_KEY = consumer.getToken();
ACCESS_SECRET = consumer.getTokenSecret();
Log.d("OAuthTwitter", ACCESS_KEY);
Log.d("OAuthTwitter", ACCESS_SECRET);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
}
Manifest.xml
<application
android:icon="#drawable/icon"
android:label="#string/app_name">
<activity
android:name=".Tweets"
android:label="#string/app_name">
<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.VIEW" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="myApp"
android:host="Tweets" />
</intent-filter>
</activity>
How do I get my application to call onResume() so that I can then continue with the OAuth process?
In this case, try setting your activity launch mode to singleTask.
See the link for more information: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode