I am trying to get NFC foreground dispatch to work in my app using the tutorials
here and here. From what I can deduce all other functions seem to be working a it is just the NFC forground dispatch system that isn't working.
In my onCreate, I check NFC exists and initialise pending Intents and filters and get the NFC adapter:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Set some stuff
mTV = (TextView) findViewById(R.id.textView);
mButt = (Button) findViewById(R.id.button);
//mNfcAd = NfcAdapter.getDefaultAdapter(this);
//Init elsewhere
getAdapter();
//Hide button until its needed
mButt.setVisibility(View.INVISIBLE);
//Make sure NFC actually exists.....
if (mNfcAd == null) {
//Not going to work without NFC
Toast.makeText(this, "This device does not support NFC\nGet used to the pen and paper for now :/", Toast.LENGTH_LONG).show();
finish();
return;
}
Intent nfcIntent = new Intent(this, getClass());
nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
nfcPendingIntent =
PendingIntent.getActivity(this, 0, nfcIntent, 0);
IntentFilter tagIntentFilter =
new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
tagIntentFilter.addDataType("text/plain");
intentFiltersArray = new IntentFilter[]{tagIntentFilter};
}
catch (Throwable t) {
t.printStackTrace();
}
//Init the prefs
initPrefs();
}
public void initPrefs() {
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
}
private NfcAdapter getAdapter(){
if(mNfcAd ==null){
NfcManager manager = (NfcManager) getSystemService(NFC_SERVICE);
mNfcAd = manager.getDefaultAdapter();
}
return mNfcAd;
}
I then go on to check NFC is enabled (if not display a button that shows NFC settings) as well as checking if the app is in its first run. At the end of onResume(), I (attempt to) enable Foreground Dispatch for the adapter.
protected void onResume() {
super.onResume();
//Define the mButt action
mButt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent dialogIntent = new Intent(Settings.ACTION_NFC_SETTINGS);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
}
});
//If NFC exists, check if its turned on
if (!mNfcAd.isEnabled()) {
Toast.makeText(this, "You have NFC, but you haven't enabled it...", Toast.LENGTH_LONG).show();
mTV.setText("NFC not enabled");
mButt.setVisibility(View.VISIBLE);
}
//Check if first run
if (prefs.getInt("firstTime", 1) == 1 ||
prefs.getString("fullName", null) == null ||
prefs.getString("house", null) == null) {
Intent intent = new Intent(this, First_Run.class);
startActivity(intent);
prefs.edit().putInt("firstTime", 0);
prefs.edit().putString("fullName", getIntent().getExtras().getString("fullName"));
prefs.edit().putString("house", getIntent().getExtras().getString("house"));
prefs.edit().apply();
}
getAdapter().enableForegroundDispatch(this, nfcPendingIntent, intentFiltersArray, null);
handleIntent(getIntent());
}
The error is:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.nfc.NfcAdapter.enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][])' on a null object reference
However, all the arguments seem to be initialised;
It is being called in onResume, so the activity context is created;
nfcPendingIntent and intentFiltersArray are initialised in onCreate;
I do not have a techlist so I use null as the final argument;
The adapter itself is initialised in getAdapter.
I am currently combing through other tutorials to see the different methods that can be used, however I would really like to get this fixed.
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.NFC" />
<application
android:fullBackupContent="false"
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>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".First_Run"
android:label="#string/title_activity_first__run">
</activity>
</application>
Try creating your NfcAdapter object like below.
NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
Related
I have an application that starts an Intent after the boot that works from Android 6 to Android 9 API level 28.
But this code does not work on Android 10 API level 29, Broadcast simply does not receive any events and does not run onReceive on MyClassBroadcastReceiver after the boot. Is there any extra permission on Android 10 or configuration that needs to be done?
Dry part of the example: Manifest:
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.softniels.autostartonboot">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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="com.softniels.autostartonboot.ForegroundService"
android:label="My Service">
<intent-filter>
<action android:name="com.softniels.autostartonboot.ForegroundService" />
</intent-filter>
</service>
<receiver
android:name=".StartMyServiceAtBootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
Here the part that doesn't run on Android 10.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("onReceive", "call onReceive ACTION_BOOT_COMPLETED");
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
I know that this may be old but I have faced the same problem and according to this:
https://developer.android.com/guide/components/activities/background-starts
The easiest solution I came up with was simply adding
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And setting up the receiver:
<receiver
android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
To the manifest.
Receiver code:
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
// Intent n = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
// n.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
// Intent.FLAG_ACTIVITY_CLEAR_TASK);
// context.startActivity(n);
Intent myIntent = new Intent(context, MainActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
}
Both options work. The only downside I see is that it takes rather a while for app to load (can be up to 10 seconds from my testings)
Leaving this here for other people if they encounter this as well.
This only applies to android 10 and up. There is a need to request "Display over other apps" permission
This requires drawing overlay, which can be done with:
if (!Settings.canDrawOverlays(getApplicationContext())) {
Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
Uri uri = Uri.fromParts("package", getPackageName(), null);
myIntent.setData(uri);
startActivityForResult(myIntent, REQUEST_OVERLAY_PERMISSIONS);
return;
}
Guess I found a 'solution' for me.
public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
Log.e(TAG, "launching from special > API 28 (" + Build.VERSION.SDK_INT + ")"); // You have to schedule a Service
JobServiceScheduler jobServiceScheduler = new JobServiceScheduler(context);
boolean result = jobServiceScheduler.scheduleMainService(20L); // Time you will wait to launch
} else {
Log.e(TAG, "launching from normal < API 29"); // You can still launch an Activity
try {
Intent intentMain = new Intent(context, YourActivity.class);
intentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT < 28) {
context.startService(intentMain);
} else {
context.startForegroundService(intentMain);
}
} catch (ActivityNotFoundException ex) {
Log.e(TAG, "ActivityNotFoundException" + ex.getLocalizedMessage());
}
}
}
boolean scheduleMainService(Long segundos) {
ComponentName serviceComponent = new ComponentName(context, YourService.class);
JobInfo.Builder builder = getCommonBuilder(serviceComponent, YOUR_SERVICE_JOB_ID);
builder.setMinimumLatency(TimeUnit.SECONDS.toMillis(segundos / 2)); // wait at least
builder.setOverrideDeadline(TimeUnit.SECONDS.toMillis(segundos)); // maximum delay
PersistableBundle extras = new PersistableBundle();
extras.putLong("time", segundos);
builder.setExtras(extras);
JobScheduler jobScheduler = getJobScheduler(context);
if (jobScheduler != null) {
jobScheduler.schedule(builder.build());
return true;
} else {
return false;
}
}
context.startActivity() is not launching, I solved it the following way:
private void restartApp( Context mContext) {
try {
long restartTime = 1000*5;
Intent intents = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intents, PendingIntent.FLAG_ONE_SHOT);
AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + restartTime, restartIntent);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I solved it with this permission in the manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
And in the main activity :
if (!Settings.canDrawOverlays(getApplicationContext())) {
startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
}
The correct import for Settings is:android.provider
The first time the app boots the permission will be prompted for controlling which apps can draw on top of other apps, the next device will start the application will boot up using the typical broadcast receiver.
Here is the doc
I am trying to send string from app to app.
First app called "send" has only "MainActivity" class and layout:
private void sendMsg(){
final TextView msg = (TextView) findViewById(R.id.sendText);
Button snd = (Button)findViewById(R.id.sendButton);
snd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!msg.getText().toString().trim().equals("")){
Intent intent = new Intent("Updated");
intent.setAction(Intent.ACTION_SEND);
intent.putExtra("TEXT", msg.getText().toString().trim());
intent.setType("text/plain");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setComponent(new ComponentName("com.example.rec","com.example.rec.broadcastReciver"));
getApplicationContext().sendBroadcast(intent);
}else{
Toast.makeText(getApplicationContext(), "Write text that You want to broadcast!", Toast.LENGTH_LONG).show();
}
}
});
}
Second app called "rec" has two classes "broadcastReciver" and "MainActivity".
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
zoviBroadCast();
}
private void zoviBroadCast(){
broadcastReciver brcv = new broadcastReciver();
registerReceiver(brcv,
new IntentFilter("action"));
}
}
broadcastReciver:
public class broadcastReciver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent)
{
//String data = intent.getStringExtra("TEXT").trim();
if (intent != null)
{
String sIntentAction = intent.getAction();
if (sIntentAction != null && sIntentAction.equals("action"))
{
String data = intent.getStringExtra("TEXT").trim();
Toast.makeText(context, data, Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(context,"Something went wrong",Toast.LENGTH_SHORT).show();
}
}
}
}
I also added lines between tag "receiver" in "AndroidManifest.xml":
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rec">
<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>
<receiver
android:name=".broadcastReciver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="action" />
</intent-filter>
</receiver>
</application>
</manifest>
What application should do is when I type something in first application and send it another over button it should "broadcast" (show) toast at second app.
My second application is not showing any data when run.
Nowadays it is essential to specify an action in intent filter of your broadcast receiver.
<receiver android:name="MyReceiver" >
<intent-filter>
<action android:name="android.intent.action.MY_ACTION">
</action>
</intent-filter>
</receiver>
When sending the broadcast, you need to set exactly the same action to the intent you send.
Intent i = new Intent();
i.setAction("android.intent.action.MY_ACTION");
context.sendBroadcast(i);
Notation of action name may be not very important to get your code working, but I recommend to give names related to the package of your sending app.
For example: "com.username.example.myApplication.ACTION_EXAMPLE"
This question already has an answer here:
Android: How do I temporarily handle an Intent in a different activity of my application?
(1 answer)
Closed 3 years ago.
I've got an android app with several activities. I want the current activity to handle the nfc discovered event, as the state of the app determines what i want to do with the tag
As can be seen in the attached code i've set up the intents on each activity and implemented the onResume, onPause and onNewIntent methods in each activty.
Yet, for some reason the MainActivty is the only one which gets called even though one of the other activities is the active one. Eg. it is the one with the current GUI.
You guys have any idea how to get the active activity to handle the NFC discovered?
Any help greatly appreciated :)
Here is the ApplicationManifest
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<activity
android:name=".ConfigureStableNamesActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED " />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.nxp.com"
android:pathPrefix="/products/identification_and_security/smart_label_and_tag_ics/ntag/series/NT3H1101_NT3H1201.html"
android:scheme="http" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- <action android:name="android.nfc.action.ACTION_TAG_DISCOVERED"/>-->
<action android:name="android.nfc.action.NDEF_DISCOVERED " />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.nxp.com"
android:pathPrefix="/products/identification_and_security/smart_label_and_tag_ics/ntag/series/NT3H1101_NT3H1201.html"
android:scheme="http" />
</intent-filter>
</activity>
In each of my activities i have this code to handle the NFC discovered intent
#Override
protected void onResume() {
super.onResume();
ntagHandler.start();
}
#Override
protected void onPause() {
super.onPause();
ntagHandler.stop();
}
#Override
protected void onNewIntent(Intent intent) {
try {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
nfcHandler = new NearFieldCommunicationHandler(tag);
nfcHandler.connect();
// DO SOMETHING HERE
// dataModel.readStableNames(nfcHandler);
} catch(IOException e) {
Toast.makeText(this, "Caught exception: " + e.toString(), Toast.LENGTH_LONG).show();
}
}
You need to implement "The foreground dispatch system". it allows an activity to intercept an intent and claim priority over other activities. Please refer: https://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc#java
First create pendingIntent globally in your each activities as below:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
then take IntentFilter globally and init with null as below:
IntentFilter[] intentFiltersArray = null;
Write below code in onCreate() method:
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* YOU CAN TYPE HERE EITHER android.nfc.action.NDEF_DISCOVERED or
android.nfc.action.ACTION_TAG_DISCOVERED */
}
catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
then take techListsArray globally as below:
String[][] techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
Finally write below code to enable and disable the foreground dispatch when the activity loses (onPause()) and regains (onResume()) focus. enableForegroundDispatch() must be called from the main thread and only when the activity is in the foreground (calling in onResume() guarantees this)
public void onPause() {
super.onPause();
nfcadapter.disableForegroundDispatch(this);
}
public void onResume() {
super.onResume();
nfcadapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}
public void onNewIntent(Intent intent) {
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//do something with tagFromIntent
}
I'm trying to read USSD response to get Sim balance amount etc, and I'm having issues, I have been reading many questions related to that on Stackoverflow, nothing has worked so far. Except for this that came close: Prevent USSD dialog and read USSD response?. by #HenBoy331
But i'm still having issues with it. My broadcast receiver doesn't get called too. I'm using 4.4.2
But it shows nothing. I can't seem to parse the message and get the balance.
I have a MainActivity to make the phone call, ReceiverActivity to implement broadcast receiver, USSDService class to get the USSD response.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, USSDService.class));
dailNumber("100");
}
private void dailNumber(String code) {
String ussdCode = "*" + code + Uri.encode("#");
startActivity(new Intent("android.intent.action.CALL", Uri.parse("tel:" + ussdCode)));
}
}
RecieverActivity.java
public class RecieverActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter("com.times.ussd.action.REFRESH");
this.registerReceiver(new Receiver(), filter);
}
public class Receiver extends BroadcastReceiver {
private String TAG = "XXXX";
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.i(TAG, "Got message: " + message);
}
}
}
USSDService.java
public class USSDService extends AccessibilityService {
public String TAG = "XXXX";
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent");
AccessibilityNodeInfo source = event.getSource();
/* if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !event.getClassName().equals("android.app.AlertDialog")) { // android.app.AlertDialog is the standard but not for all phones */
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !String.valueOf(event.getClassName()).contains("AlertDialog")) {
return;
}
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && (source == null || !source.getClassName().equals("android.widget.TextView"))) {
return;
}
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && TextUtils.isEmpty(source.getText())) {
return;
}
List<CharSequence> eventText;
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
eventText = event.getText();
} else {
eventText = Collections.singletonList(source.getText());
}
String text = processUSSDText(eventText);
if( TextUtils.isEmpty(text) ) return;
// Close dialog
performGlobalAction(GLOBAL_ACTION_BACK); // This works on 4.1+ only
Log.d(TAG, text);
// Handle USSD response here
Intent intent = new Intent("com.times.ussd.action.REFRESH");
intent.putExtra("message", text);
sendBroadcast(intent);
}
private String processUSSDText(List<CharSequence> eventText) {
for (CharSequence s : eventText) {
String text = String.valueOf(s);
// Return text if text is the expected ussd response
if( true ) {
return text;
}
}
return null;
}
#Override
public void onInterrupt() {
}
#Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "onServiceConnected");
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.flags = AccessibilityServiceInfo.DEFAULT;
info.packageNames = new String[]{"com.android.phone"};
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
setServiceInfo(info);
}
}
AndroidManifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.dialussd">
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".services.USSDService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/config_service" />
</service>
<receiver android:name=".RecieverActivity$Receiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Please, is there any way i'm implementing this wrongly, Or perhaps there is a new way to get USSD responses which works?
After the launch, change the settings manually
Setting->Accessibility Setting -> You can see a option 'your app name'. Turn it on. (This has to be done from as a part of application flow(not manual))
instead of using broadcast receiver use these two lines of code in
add this code in MainActivity
public static void setTextViewToModify(String Text) {
textView.setText(Text);}
and add this in service class with in onAccessibityEvent
MainActivity.setTextViewToModify(text);
I already found others questions similar to mine, but could not find the solution. I have a custom widget with simple TextView and also a configuration Activity. Problem is:
When widget is added to homescreen, configurations activity appears, but onUpdate() method of AppWidgetProvider runs immediately, as soon as configuration activity is created. It should run after configuration activity is closed by pressing OK button.
Even if onUpdate() method run on configuration activity start (according to Toast in the method,showing proper data for textview), the TextView remains still not updated.
Even if android:updatePeriodMillis is set to 1000ms, onUpdate method run only once - when configuration activity starts.
When I add the widget to my homescreen and then restart phone, the widget's TextView is finally updated with proper time, but only once.
Many users have been reporting similar problems on recent android versions, like 4.4. Is there any final solution for this bad behavior?
Here are my files - Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="incredible.riskofrain.app">
<application android:allowBackup="true"
android:label="#string/app_name"
android:icon="#drawable/main_icon">
<receiver android:name=".RORAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/ror_appwidget_info" />
</receiver>
<activity android:name=".RORAppWidgetConfigure">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity android:name="incredible.riskofrain.app.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
appwidget_info:
android:minWidth="200dp"
android:minHeight="80dp"
android:updatePeriodMillis="1000"
android:initialLayout="#layout/ror_appwidget"
android:configure="incredible.riskofrain.app.RORAppWidgetConfigure"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen" >
AppWidgetProvider:
public class RORAppWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
Calendar c = Calendar.getInstance();
String time = "" + c.get(Calendar.MINUTE)+ ":" + c.get(Calendar.SECOND);
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.ror_appwidget);
views.setTextViewText(R.id.textview, time);
appWidgetManager.updateAppWidget(appWidgetId, views);
Toast.makeText(context, "onUpdate " + time + " " + appWidgetId, Toast.LENGTH_LONG).show();
}
}}
AppWidgetConfigure:
public class RORAppWidgetConfigure extends Activity {
int appWidgetId; Button button; AppWidgetManager appWidgetManager;
RemoteViews views;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.ror_configure);
button = (Button) findViewById(R.id.button);
appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
Bundle extras = getIntent().getExtras();
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
views = new RemoteViews(getPackageName(), R.layout.ror_appwidget);
appWidgetManager.updateAppWidget(appWidgetId, views);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, resultValue);
Toast.makeText(getApplication().getApplicationContext(), "Configure, ID: - " + appWidgetId+"", Toast.LENGTH_LONG).show();
finish();
}
});
super.onCreate(savedInstanceState);
}}
you can update Widget using broasdcast Receiver ..
check this link:
Reference Link
<!-- Broadcast Receiver that will process AppWidget updates -->
<receiver android:name=".WordWidget" android:label="#string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_word" />
</receiver>
i hope its useful to you..
I found this in documentation, probably this is the problem:
public int updatePeriodMillis
Added in API level 3
How often, in milliseconds, that this AppWidget wants to be updated. The AppWidget manager may place a limit on how often a AppWidget is updated.
This field corresponds to the android:updatePeriodMillis attribute in the AppWidget meta-data file.
Note: Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes.
I also found that there is a huge bug in android framework making configuration activity useless: https://code.google.com/p/android/issues/detail?id=3696