Trying to understand the BroadcastReceiver in android coding - java

First off am a complete newbie to Android coding and the logic is really confusion me. Originally im Flash developer and im familiar with concepts from there, while Android is complete set of new concepts. For example (correct me if im wrong) a Intent is like an Event and BroadcastReceiver is a EventListener ?
Well it is here im stuck, if it is so, Intent is Event and broadcastReceiver is eventListener then my question is how do i assign a variable, data that ive handeled in onReceive method ?
Ive been searching for long time now and really get angry at myself for not understanding the logic. Im trying to compare and associate things to ActionScript3 and Javascript (some stuff in JS is pretty close to AS3).
Now to the code im trying to write and the problem i got.
Im trying to get myself into writing a Android Native Extension for Adobe AIR...
So, far so good at least in some way :)
The manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.as3breeze.air"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".BluetoothExtension"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
As i see, the main activity is my BluetoothExtension.java which is following:
Notice it implements FREExtension (created by Adobe for Native Extensions)
package com.as3breeze.air;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREExtension;
import com.as3breeze.air.BluetoothExtensionContext;
public class BluetoothExtension implements FREExtension {
protected BluetoothExtensionContext BEC;
/** Called when the activity is first created. */
#Override
public FREContext createContext(String arg0) {
BEC = new BluetoothExtensionContext();
return BEC;
}
#Override
public void dispose() {
// TODO Auto-generated method stub
BEC.dispose();
BEC = null;
}
#Override
public void initialize() {}
}
Thats the Activity, right ?
And it creates Context which is following (am leaving out the #imports):
public class BluetoothExtensionContext extends FREContext {
public BluetoothAdapter bluetooth;
public Activity extensionActivity;
public FREArray nonBoundedDevices;
#Override
public void dispose() {
// TODO Auto-generated method stub
}
#Override
public Map<String, FREFunction> getFunctions() {
Map<String, FREFunction> functionMap=new HashMap<String, FREFunction>();
functionMap.put("initialize", new Initialize());
// Leaving out some stuff here and listing only the important things...
functionMap.put("listDevices", new ListAvailableDevices());
return functionMap;
}
}
Now, as you see above i got some public vars for easier access, those are initiated inside new Initialize() which looks like this:
package com.as3breeze.air;
import android.bluetooth.BluetoothAdapter;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;
import com.adobe.fre.FREWrongThreadException;
import com.as3breeze.air.BluetoothExtensionContext;
public class Initialize implements FREFunction {
#Override
public FREObject call(FREContext context, FREObject[] args) {
BluetoothExtensionContext bluetoothContext = (BluetoothExtensionContext) context;
bluetoothContext.bluetooth = BluetoothAdapter.getDefaultAdapter();
bluetoothContext.extensionActivity = bluetoothContext.getActivity();
FREObject returnData = null;
if( bluetoothContext.bluetooth == null )
{
try {
returnData = FREObject.newObject("notSupported");
} catch (FREWrongThreadException e) {}
}
return returnData;
}
}
Initiation works fine, i also got other methods listed in the Map such as enabling / disabling bluetooth, discoverability and few more, everything there works well.
But the problem is in this one: functionMap.put("listDevices", new ListAvailableDevices());
The class is created and running and returning, it looks like this:
package com.as3breeze.air;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import com.adobe.fre.FREASErrorException;
import com.adobe.fre.FREArray;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREInvalidObjectException;
import com.adobe.fre.FREObject;
import com.adobe.fre.FRETypeMismatchException;
import com.adobe.fre.FREWrongThreadException;
public class ListAvailableDevices implements FREFunction {
static FREArray returnDevicesArr = null;
#Override
public FREObject call(FREContext context, FREObject[] args) {
BluetoothExtensionContext bluetoothContext = (BluetoothExtensionContext) context;
returnDevicesArr = bluetoothContext.nonBoundedDevices;
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int index = 0;
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice bt = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText( context, "Searching devices...", Toast.LENGTH_SHORT).show();
FREArray deviceName;
try {
deviceName = FREArray.newArray(1);
deviceName.setObjectAt(0, FREObject.newObject(bt.getName()));
deviceName.setObjectAt(1, FREObject.newObject(bt.getAddress()));
returnDevicesArr.setObjectAt(index, deviceName);
index++;
} catch (FREASErrorException e) {
e.printStackTrace();
} catch (FREWrongThreadException e) {
e.printStackTrace();
} catch (FREInvalidObjectException e) {
e.printStackTrace();
} catch (FRETypeMismatchException e) {
e.printStackTrace();
}
}
}
};
bluetoothContext.extensionActivity.registerReceiver(mReceiver, filter);
bluetoothContext.bluetooth.startDiscovery();
return null; // Or to use return returnDeviceArr;
}
}
As you see, im trying to store all found devices in returnDeviceArr either to return from call() or in some "global" variable defined in BluetoothExtensionContext.java, it does not matter which way to go, i just need to get hold of that data.
Im not being able to reach the returnDeviceArr variable from onReceive method. Ive also tested to create a new FREArray inside onReceive and store devices data there, so it can be returned but return null; at bottom of call(){ ... } is fired and ultimately giving me null value.
So, how can i make it possible to replace that return null with return returnDeviceArr; and get the array of available devices ?
Im hoping for code examples and explanations so i can start to understand Android coding without using visual components.

The BlueToothExtension class must extend the activity class. Declaring in the manifest alone is not enough. And you should register your broadcast receiver with the intent. Check out the android development guide for more detail.
For Intents to pass variables, you should put them in extras like
`Intent intent = new Intent(this, target.class);
intent.putExtra("variable", value);
startActivityForResult(intent, request_Code);`
In the target class you can fetch the variable using intent.getStringExtra("variable");

Related

How to navigate to specific activity/fragment after tapping on one signal push notification?

can someone provide me the proper documentation or code to navigate to specific activity by tapping on one signal push notification, i want to open the specific fragment
here is my code where i extened application class and initialize one signal :
package com.example.nasapp;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Parcelable;
import android.util.Log;
import com.example.nasapp.ui.home.HomeFragment;
import com.example.nasapp.ui.information.InformationFragment;
import com.onesignal.OSMutableNotification;
import com.onesignal.OSNotification;
import com.onesignal.OSNotificationAction;
import com.onesignal.OSNotificationOpenedResult;
import com.onesignal.OSNotificationReceivedEvent;
import com.onesignal.OneSignal;
import org.json.JSONException;
import org.json.JSONObject;
public class OneSignalApplication extends Application {
private static final String ONESIGNAL_APP_ID = "e855e254-9b4e-4e6f-a64a-e48db6f35d07";
#Override
public void onCreate() {
super.onCreate();
// Enable verbose OneSignal logging to debug issues if needed.
//OneSignal.setLogLevel(OneSignal.LOG_LEVEL.VERBOSE, OneSignal.LOG_LEVEL.NONE);
// OneSignal Initialization
OneSignal.initWithContext(this);
OneSignal.setAppId(ONESIGNAL_APP_ID);
// promptForPushNotifications will show the native Android notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 7)
OneSignal.promptForPushNotifications();
OneSignal.setNotificationOpenedHandler(new OneSignal.OSNotificationOpenedHandler() {
#Override
public void notificationOpened(OSNotificationOpenedResult result) {
JSONObject data = result.getNotification().getAdditionalData();
Log.i("OneSignalExample", "Notification Data: " + data);
String notification_topic;
if (data != null) {
try {
System.out.println(data.getString("job_id"));
} catch (JSONException e) {
e.printStackTrace();
}
notification_topic = data.optString("notification_topic", "hii");
if (notification_topic != null) {
OneSignal.addTrigger("level", notification_topic);
}
}
}
});
}
}
here is my NotificationServiceExtensionClass:
public class NotificationServiceExtension extends Service implements OneSignal.OSRemoteNotificationReceivedHandler {
#Override
public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent notificationReceivedEvent) {
OSNotification notification = notificationReceivedEvent.getNotification();
// Example of modifying the notification's accent color
OSMutableNotification mutableNotification = notification.mutableCopy();
mutableNotification.setExtender(builder -> {
//... do stuff
builder.setTimeoutAfter(30000);
Intent intent = new Intent();
JSONObject data = notification.getAdditionalData();
// check the data and create intent
intent = new Intent(context, InformationFragment.class);
// or any other depends on data value
intent.putExtra("data", (Parcelable) data);
PendingIntent pendIntent = PendingIntent.getActivity(context,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder = builder.setContentIntent(pendIntent);
return builder;
});
JSONObject data = notification.getAdditionalData();
Log.i("OneSignalExample", "Received Notification Data: " + data);
// If complete isn't call within a time period of 25 seconds, OneSignal internal logic will show the original notification
// To omit displaying a notification, pass `null` to complete()
notificationReceivedEvent.complete(mutableNotification);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
In manifest i declare this service class:
<service
android:name=".service.NotificationServiceExtension"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
am i missing some code or what am i doing wrong in code ,can please someone help?

Saving Text Files - Scoped Storage Android 11

Is there a way to create and save text files outside of the Android/data folder in external storage? I am creating a music app and I added a preset manager so users can save, load, and edit preset files (which worked great before Android 11), I don’t want these files to be automatically removed if the app is uninstalled. That would be like if Photoshop deleted all of your Photoshop documents when Photoshop is uninstalled, that’s terrible! These are files that the user saves and they can be deleted separately if the user wants to.
There has to be a way around this but I haven’t been able to find anything that works. ACTION_OPEN_DOCUMENT_TREE looked very promising, until I saw that Android has removed this option too.
https://developer.android.com/about/versions/11/privacy/storage
You can no longer use the ACTION_OPEN_DOCUMENT_TREE intent action to
request access to the following directories:
The root directory of the internal storage volume.
The root directory of each SD card volume that the device manufacturer considers to be reliable, regardless of whether the card
is emulated or removable. A reliable volume is one that an app can
successfully access most of the time.
The Download directory.
I’ve read Google Play only allows MANAGE_EXTERNAL_STORAGE in apps that need it (like file browsers, or anti-virus, etc) which likely will not work in my case. I don’t want to rely on only targeting older API’s so requestLegacyExternalStorage won’t work either.
Everything I’ve looked into appears to be a dead end. Is there anything else I can do?
Here is a short test program (I’m using LibGDX), which at the moment can only save to the root location:
Android/data/com.mygdx.filetest/files/
[core] FileTest.java
package com.mygdx.filetest;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.ScreenUtils;
public class FileTest implements ApplicationListener {
private NativePermissions permissions;
private Files.FileType fileType;
private String directory = "TestDir/";
private String name = "text.txt";
public FileTest(final NativePermissions permissions){
this.permissions = permissions;
}
#Override
public void create(){
fileType = getFileType();
if (permissions != null){
permissions.checkExternalStoragePermission();
} else {
permissionGranted();
}
}
private Files.FileType getFileType(){
switch(Gdx.app.getType()) {
case Android:
return Files.FileType.External;
default:
return Files.FileType.Local;
}
}
#Override public void render(){ ScreenUtils.clear(0.4f, 0.4f, 0.4f, 1); }
#Override public void resize(int width, int height) {}
#Override public void pause(){}
#Override public void resume(){}
#Override public void dispose (){}
public void permissionGranted() {
FileHandle fileHandle = Gdx.files.getFileHandle(directory+name, fileType);
if (fileHandle!=null) fileHandle.writeString("test", false);
}
}
[android] AndroidLauncher.java
package com.mygdx.filetest;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
public class AndroidLauncher extends AndroidApplication {
private final FileTest application;
private final int STORAGE_PERMISSION_CODE = 1;
private boolean dialogBoxShowing = false;
public AndroidLauncher(){
final AndroidPermissions permissions = new AndroidPermissions(this);
application = new FileTest(permissions);
}
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(application, config);
}
#Override
public void onRequestPermissionsResult(final int requestCode, final String permissions[], final int[] grantResults) {
dialogBoxShowing = false;
if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission GRANTED", Toast.LENGTH_SHORT).show();
permissionGranted();
} else {
Toast.makeText(this, "Permission DENIED", Toast.LENGTH_SHORT).show();
}
}
}
public void promptExternalStoragePermission() {
if (dialogBoxShowing) return;
dialogBoxShowing = true;
this.runOnUiThread(new Runnable() {
#Override
public void run() {
final AlertDialog.Builder builder = new AlertDialog.Builder(AndroidLauncher.this);
builder.setMessage("To save user presets and custom settings, allow access to your phone’s storage.");
builder.setCancelable(false);
// reverse these buttons to put "NO" on left and "YES" on right
builder.setPositiveButton("NOT NOW", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
dialogBoxShowing = false;
dialog.dismiss();
}
});
builder.setNegativeButton("CONTINUE", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(AndroidLauncher.this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
});
builder.create().show();
}
});
}
public void permissionGranted(){ application.permissionGranted(); }
}
[core] NativePermissions.java
package com.mygdx.filetest;
public interface NativePermissions {
public void checkExternalStoragePermission();
}
[android] AndroidPermissions.java
package com.mygdx.filetest;
import android.Manifest;
import android.content.pm.PackageManager;
import androidx.core.content.ContextCompat;
public class AndroidPermissions implements NativePermissions {
private final AndroidLauncher context;
public AndroidPermissions(final AndroidLauncher context){
this.context = context;
}
#Override
public void checkExternalStoragePermission() {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
context.permissionGranted();
} else {
context.promptExternalStoragePermission();
}
}
}
[android] AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mygdx.filetest">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:isGame="true"
android:appCategory="game"
android:label="#string/app_name"
android:theme="#style/GdxTheme" >
<activity
android:name="com.mygdx.filetest.AndroidLauncher"
android:label="#string/app_name"
android:screenOrientation="fullUser"
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
A lott of fuss.
You can in the classic way save your files to the public Documents directory.
Or use SAF with ACTION_OPEN_DOCUMENT_TREE for that directory.
Both dont need 'all files access'.

bindService android AIDL always return false

I would like to provide a service that can be called by other app. Therefore, I have a service and an aidl. But when I try to have a separate application to bind this service (bindService), it just returns me false which means fail. Here is my code.
I'm using the code from books Pro Android 2
I've already tried many solutions in other questions similar to this, but there isn't any working solution for me.
I've tried fix the aidl intent filter but it's still not working
I've tried fix the package name and class name in client app, but it's still not working.
Please help me!
On Client :
// IStockQuoteService.aidl
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;
// Declare any non-default types here with import statements
interface IStockQuoteService {
double getQuote(String ticker);
}
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteclient;
import id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice.IStockQuoteService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
protected static final String TAG = "StockQuoteClient";
private IStockQuoteService stockService = null;
private Button bindBtn;
private Button callBtn;
private Button unbindBtn;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindBtn = (Button)findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
".ahmad_fauzan_amirul_isnain.stockquoteservice",
"com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
".stockquoteservice.IStockQuoteService");
Log.d("Hasil", String.valueOf(bindService(intent,
serConn, Context.BIND_AUTO_CREATE)));
bindBtn.setEnabled(false);
callBtn.setEnabled(true);
unbindBtn.setEnabled(true);
}});
callBtn = (Button)findViewById(R.id.callBtn);
callBtn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view) {
callService();
}});
callBtn.setEnabled(false);
unbindBtn = (Button)findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view) {
unbindService(serConn);
bindBtn.setEnabled(true);
callBtn.setEnabled(false);
unbindBtn.setEnabled(false);
}});
unbindBtn.setEnabled(false);
}
private void callService() {
try {
double val = stockService.getQuote("SYH");
Toast.makeText(MainActivity.this, "Value from service is "+val,
Toast.LENGTH_SHORT).show();
} catch (RemoteException ee) {
Log.e("MainActivity", ee.getMessage(), ee);
}
}
private ServiceConnection serConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.v(TAG, "onServiceConnected() called");
stockService = IStockQuoteService.Stub.asInterface(service);
callService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.v(TAG, "onServiceDisconnected() called");
stockService = null;
}
};
}
On Service :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice">
<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="StockQuoteService">
<intent-filter>
<action android:name="com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice.IStockQuoteService"
/>
</intent-filter>
</service>
</application>
</manifest>
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class StockQuoteService extends Service
{
private static final String TAG = "StockQuoteService";
public class StockQuoteServiceImpl extends IStockQuoteService.Stub
{
#Override
public double getQuote(String ticker) throws RemoteException
{
Log.v(TAG, "getQuote() called for " + ticker);
return 20.0;
}
}
#Override
public void onCreate() {
super.onCreate();
Log.v(TAG, "onCreate() called");
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.v(TAG, "onDestroy() called");
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.v(TAG, "onStart() called");
}
#Override
public IBinder onBind(Intent intent)
{
Log.v(TAG, "onBind() called");
return new StockQuoteServiceImpl();
}
}
// IStockQuoteService.aidl
package id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice;
// Declare any non-default types here with import statements
interface IStockQuoteService {
double getQuote(String ticker);
}
I'm using the code from books Pro Android 2
That book is from 2010. Much of that book will be out of date. Please use something newer. If nothing else, you can download older editions of one of my books for free. Right now, the most recent version of those is from 2015 — while that too is a bit old, it is much more up to date than a book from 2010.
I've already tried many solutions in other questions similar to this, but there isn't any working solution for me.
You have:
intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
".ahmad_fauzan_amirul_isnain.stockquoteservice",
"com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
".stockquoteservice.IStockQuoteService");
The package in your manifest has id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain.stockquoteservice. Assuming that your applicationId in your module's build.gradle file is the same, I think that this matches what you have in your code. Your application ID is very long — in the future, I recommend that you use something shorter and easier to visually compare.
However, your class name is wrong. Your <service> class is StockQuoteService, not IStockQuoteService. IStockQuoteService is the name of the AIDL, not the service, and your Intent needs to point to the service. So, try:
intent.setClassName("com.id.ac.ui.cs.mobileprogramming" +
".ahmad_fauzan_amirul_isnain.stockquoteservice",
"com.id.ac.ui.cs.mobileprogramming.ahmad_fauzan_amirul_isnain" +
".stockquoteservice.StockQuoteService");
Or, to reduce duplication:
String packageName = "com.id.ac.ui.cs.mobileprogramming" +
".ahmad_fauzan_amirul_isnain.stockquoteservice";
intent.setClassName(packageName, packageName+".StockQuoteService");

How to call an activity's methods from a separate class

So I've been playing around with Android M style permissions and I have a working demo so long as I do everything from within the MainActivity. I felt that it looked to cumbersome and wanted to split that in to multiple files so it looked a little cleaner and could be more easily maintained.
The problem is by moving the permissions checking into its own file, I am having trouble now getting my permissions checker to go back to MainActivity and launch the demo() method. Where I need to call back to main activities demo method is on line 73 and line 114 of the PermissionsChecker.java
NOTE: I followed this tutorial on Android Permissions
I have found this question as well as these questions here & here. I realize this is dangerously close to a duplicate of the last two, they got me close but I haven't quite been able to get it. If someone can break it down a little more for me, I am still fairly new to Java and Android.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="me.johnweland.androidrtp"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- // Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- // Features -->
<uses-feature android:name="android.hardware.camera" />
<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>
</application>
</manifest>
MainActivity.java
package me.johnweland.androidrtp;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23) {
// Marshmallow+
PermissionChecker permissions = PermissionChecker.getInstance(this);
permissions.permissionsCheck();
} else {
// Pre-Marshmallow
demo();
}
}
#TargetApi(Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
{
Map<String, Integer> perms = new HashMap<String, Integer>();
// Initial
perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
// Fill with results
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for RECORD_AUDIO
if (perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// All Permissions Granted
demo();
}
else {
// Permission Denied
Toast.makeText(this, R.string.permission_denied_message, Toast.LENGTH_SHORT).show();
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
protected void demo() {
Toast.makeText(this, "Demo toast", Toast.LENGTH_LONG).show();
}
}
PermissionsChecker.java
package me.johnweland.androidrtp;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jweland on 12/11/2015.
*/
public class PermissionChecker {
private static final String TAG = PermissionChecker.class.getSimpleName();
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 0;
private MainActivity mainActivity;
private static PermissionChecker instance = null;
private PermissionChecker(MainActivity activity) {
mainActivity = activity;
}
static public PermissionChecker getInstance(MainActivity activity) {
if (instance == null) {
instance = new PermissionChecker(activity);
return instance;
} else {
return instance;
}
}
#TargetApi(Build.VERSION_CODES.M)
protected void permissionsCheck(){
List<String> permissionsNeeded = new ArrayList<String>();
final List<String> permissionsList = new ArrayList<String>();
// Add permission check for any permission that is not NORMAL_PERMISSIONS
if(!addPermission(permissionsList, Manifest.permission.RECORD_AUDIO))
permissionsNeeded.add(mainActivity.getString(R.string.permission_microphone));
if(!addPermission(permissionsList, Manifest.permission.CAMERA))
permissionsNeeded.add(mainActivity.getString(R.string.permission_camera));
if(permissionsList.size() > 0) {
if(permissionsNeeded.size() > 0) {
// Need Rationale
String message = mainActivity.getString(R.string.permission_grant_message) + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + "\n" +permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener() {
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onClick(DialogInterface dialog, int which) {
mainActivity.requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
}
});
return;
}
mainActivity.requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
return;
}
mainActivity.demo();
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(mainActivity)
.setMessage(message)
.setPositiveButton(R.string.dialog_ok_button_text, okListener)
.setNegativeButton(R.string.dialog_cancel_button_text, null)
.create()
.show();
}
#TargetApi(Build.VERSION_CODES.M)
private boolean addPermission(List<String> permissionsList, String permission) {
if (mainActivity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (!mainActivity.shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
}
Initially in the last code block on lines 73 and 114 I had tried something to the effect of "MainActivity.demo();" where "demo();" is the method I wish to call.
You can make your class ask for your activity as a parameter, save it on a variable and call it's method whenever you want (assuming that your class and activity run on the same thread).
public class MyActivity extends AppCompatActivity
{
public void myFunction() {/* ... */}
}
public class MyClass
{
MyActivity activity;
//This could be the constructor
public void someFunction(MyActivity gActivity)
{
activity = gActivity;
}
public void anotherFunction()
{
//From activity you can get everything you want like context
//resources and anything else
activity.myFunction();
}
}
Another way you could do it is by creating an interface which saves a function (on your activity) and passes that interface as argument to your class and calls it whenever you want, but that's slightly more complicated, the first method is better in my opinion.

Simple UPnP / DLNA control point for Android using CyberGarage CyberLink for Java

I want to write a UPnP control point application for Android using the CyberGarage "CyberLink for Java" API. To test the API I implemented a very simple application. In this application a UPnP control point actively searches for any UPnP root devices, listens for responses and device notifications, and prints a list of the devices, which are available on the network.
The app runs on an Android phone, but none of the UPnP devices on my network are found. I tried this on two different Android phones. To check out if this is an Android specific problem, I implemented the same functionality as a Java console application. Interestingly enough the Java console application works absolutely fine and always shows all of the UPnP devices on my network!
So why does this not work on Android? Note, in the Android app I had to implement the network specific functionality on a seperate thread using AsyncTask. Otherwise I get errors, because I am not supposed to run this on the UI thread. But this should not be the problem, am I right?
Below the source code of the two applications.
Android application:
MainActivity.java
package com.example.controller_v1;
import org.cybergarage.upnp.DeviceList;
import org.cybergarage.upnp.UPnP;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UPnP.setEnable(UPnP.USE_ONLY_IPV4_ADDR);
new StartControlPointTask().execute();
}
private class StartControlPointTask extends AsyncTask {
public static final String TAG = "StartControlPointTask";
#Override
protected Object doInBackground(Object... params) {
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
MyControlPoint controlPoint = new MyControlPoint();
controlPoint.start();
// controlPoint.search();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
DeviceList rootDevices = controlPoint.getDeviceList();
int numDevices = rootDevices.size();
if (numDevices > 0) {
for (int i = 0; i < numDevices; i++) {
Log.i(TAG, "device " + i + ": " + rootDevices.getDevice(i).getFriendlyName());
}
} else {
Log.i(TAG, "no root devices found");//
}
return null;
}
}
}
MyControlPoint.java
package com.example.controller_v1;
import org.cybergarage.upnp.ControlPoint;
import org.cybergarage.upnp.device.NotifyListener;
import org.cybergarage.upnp.device.SearchResponseListener;
import org.cybergarage.upnp.ssdp.SSDPPacket;
import android.util.Log;
public class MyControlPoint extends ControlPoint implements NotifyListener, SearchResponseListener {
public MyControlPoint() {
addNotifyListener(this);
addSearchResponseListener(this);
}
#Override
public void deviceNotifyReceived(SSDPPacket ssdpPacket) { // NotifyListener
final String TAG = "deviceNotifyReceived";
Log.i(TAG, "executed");
}
#Override
public void deviceSearchResponseReceived(SSDPPacket ssdpPacket) { // SearchResponseListener
final String TAG = "deviceSearchResponseReceived";
Log.i(TAG, "executed");
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.controller_v1"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.controller_v1.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>
</application>
</manifest>
Java console application:
Main.java
import org.cybergarage.upnp.DeviceList;
import org.cybergarage.upnp.UPnP;
public class Main {
public Main() {
UPnP.setEnable(UPnP.USE_ONLY_IPV4_ADDR);
MyControlPoint controlPoint = new MyControlPoint();
controlPoint.start();
// controlPoint.search();
try {
Thread.sleep(5000); // wait for devices to be found
} catch (InterruptedException e) {
e.printStackTrace();
}
DeviceList rootDevices = controlPoint.getDeviceList();
int numDevices = rootDevices.size();
if (numDevices > 0) {
for (int i = 0; i < numDevices; i++) {
System.out.println("found device " + i + ": " + rootDevices.getDevice(i).getFriendlyName());
}
} else {
System.out.println("no root devices found");
}
}
public static void main(String[] args) {
new Main();
}
}
MyControlPoint.java
import org.cybergarage.upnp.ControlPoint;
import org.cybergarage.upnp.device.NotifyListener;
import org.cybergarage.upnp.device.SearchResponseListener;
import org.cybergarage.upnp.ssdp.SSDPPacket;
public class MyControlPoint extends ControlPoint implements /*DeviceChangeListener,*/ NotifyListener, SearchResponseListener {
public MyControlPoint() {
addNotifyListener(this);
addSearchResponseListener(this);
}
#Override
public void deviceNotifyReceived(SSDPPacket packet) { // NotifyListener
System.out.println("deviceNotifyReceived");
}
#Override
public void deviceSearchResponseReceived(SSDPPacket packet) { // SearchResponseListener
System.out.println("deviceSearchReceived");
}
}
I don't have any idea, why the java console application works and the android application doesn't. I don't get any answer from the documentation. Can anybody help me?
I lifted your code, compiled it using Eclipse ADT and it ran perfectly on a virtual machine (VMWare player) running Android 4.0 (eeepc).
There is an Android section on CyberGarage website that does say that CyberLink doesn't run on the emulator yet as it doesn't support multicast yet, perhaps that is/was your problem.
Hope not too late to help.
Andrew
In my case it is displaying all the devices, may be because I'm checking with Phone rather emulator.

Categories

Resources