When I run my code in Debug from Android Studio my app work good, but when I create the APK and install it on device and start my app, the app get NullPointerException error and get killed( using Android Debug Monitor). Here is the code:
public class MusicService extends IntentService {
boolean INTERNET_CONNECTION = false;
boolean COMMAND_DOWNALOAD_SDCARD = false;
String TABLE_NAME = "";
String COMMAND_ARGUMENT = "";
// Here throw sometimes the error - Line 42
AudioManager audio;
MediaPlayer mp = new MediaPlayer();
long TIME_ELAPSED = 0;
long TIME_STARTED = 0;
boolean ALIVE = true;
long SLEEP_TIME = 5000;
String SERVER_URL = "http://xxx.xxx";
public MusicService() {
super("Service");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("SERVICE", "STARTED");
initialize();
initializeTimer();
while (ALIVE) {
...
}
}
private void initialize() {
// Get phone number set the table name
TABLE_NAME = "t" + getPhoneNumber();
audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// Wait for internet connection
INTERNET_CONNECTION = waitInternetConnection();
Log.d("INITIALIZE", "COMPLETED");
}
...
}
I start my app when boot is completed. After some times of trying to run it I got error at line 42 and I changed the line from:
AudioManager audio = null;
to
AudioManager audio;
But still get the error but now don't show any more the line.
There is no difference between these: AudioManager audio = null; and AudioManager audio;.
Changing the line from explicitly assigning null to the object doesn't change any functionality at all; all it means is that audio now implicitly defaults to null.
Clearly there is a difference in what getSystemService() does, depending on whether you're in your debugging environment versus your production environment. To find out what's wrong, go into that service. We don't have enough information here to debug it for you.
audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Related
I am trying to build calling app like what's app. When user call to another user then beep beep lopping sound start util call accept or decine.
private val progressPlayer: MediaPlayer by lazy {
MediaPlayer.create(applicationContext, R.raw.progress_out).apply { isLooping = true }
}
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val isSpeakerOn = audioManager.isSpeakerphoneOn
if (isSpeakerOn) {
audioManager.isSpeakerphoneOn = false
}
audioManager.mode = AudioManager.MODE_IN_CALL
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0)
progressPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL)
progressPlayer.start()
I am testing this code android 13. it's not working. Sound always playing in speaker mode.
I created a Java plugin that utilizes the UsbManager devices to communicate with a specified serial device. I'm using Android Studio to run the plugin and can write to the proper device, but I don't understand how to integrate my code with Unity. I pass the Context in the constructor so I can create the UsbManager, but I don't know how to this in Unity or if there's another way to get the Context.
What's the proper way to pass the Context from Unity to my plugin? I'm also not sure if my function is working in Unity, because I don't know if permissions are needed for USB as well in the manifest file.
Unity Code:
void Start()
{
ajc = new AndroidJavaObject("com.company.dg.USBController");
int connected = ajc.Call<int>("startUSB");
}
Java Code:
public class USBController {
private Context context;
private static final String ACTION_USB_PERMISSION = "com.company.dg.USB_PERMISSION";
private final int BAUD_RATE = 19200;
private int bytesRead;
private byte[] readBuffer;
private UsbManager usbManager;
private UsbDeviceConnection connection;
private UsbSerialDevice serial;
private UsbDevice dg = null;
public USBController(Context context){
this.context = context;
}
public int startUSB(){
//usbManager = (UsbManager) context.getSystemService(context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
UsbDevice dg = null;
if(deviceList.size() == 0){
return -2;
}
// 1st and only device
dg = deviceList.values().iterator().next();
if(dg != null){
PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(dataglove, pi);
UsbDeviceConnection connection = usbManager.openDevice(dataglove);
UsbSerialDevice serial = UsbSerialDevice.createUsbSerialDevice(dg, connection);
serial.open();
serial.setBaudRate(BAUD_RATE);
serial.setDataBits(UsbSerialInterface.DATA_BITS_8);
serial.setStopBits(UsbSerialInterface.STOP_BITS_1);
serial.setParity(UsbSerialInterface.PARITY_NONE);
serial.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serial.read(callback);
} else {
return -1;
}
return 0;
}
private UsbSerialInterface.UsbReadCallback callback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] data) {
bytesRead = data.length;
readBuffer = data;
}
};
What's the proper way to pass the Context from Unity to my plugin?
C# side:
Your USBController class has a constructor that takes Context as an argument. Before calling the startUSB function, obtain the Unity Context then send it to the constructor when you're creating an instance of USBController.
Get Unity Context:
AndroidJavaClass unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject unityContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext");
Send the Context to your Java code when creating an instance of it:
ajc = new AndroidJavaObject("com.bebopsensors.dg.USBController", unityContext);
Now, you can call your startUSB function:
int connected = ajc.Call<int>("startUSB");
Java Side:
In your startUSB function, you can now use the Context with the getSystemService. I noticed you commented that out. Note that the context.USB_SERVICE should be Context.USB_SERVICE. The c in Context should be capitalized.
public int startUSB()
{
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
....
....
}
Don't know if permissions are needed for USB as well in the manifest
file.
Not really sure about that but I believe that calling the requestPermission function which you did should be enough to handle that. If this is not working then I suggest you test your Java program in Android only and Without Unity to see if it's working. If it works there, the solution I suggested should also work.
I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?
The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.
Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.
I'm trying to create a service that will continuously check the foreground application, and when the certain app comes in to the foreground, do a task. When it exits the foreground, do another task. This should occur repeatedly until the user stops the service (I have service handling done already).
I don't know how to go about this. Here is how I'm checking for the current foreground application:
/* Get all Tasks available (with limit set). */
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit);
/* Loop through all tasks returned. */
for (ActivityManager.RunningTaskInfo aTask : allTasks)
{
Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName());
if (aTask.baseActivity.getClassName().equals("package"))
running=true;
}
Then, I have a simple if/else that checks the status of running and preforms the tasks as required:
if(running =! true) {
MainActivity defaults = new MainActivity();
defaults.RunAsRoot(commandsdefault);
}
else {
MainActivity defaults = new MainActivity();
defaults.RunAsRoot(commands);
}
Now, that doesn't run continuously, it just does it once and stops. So, I put the entirety of my onCreate() inside a while():
boolean justrun = true;
while(doit = true) {
//everything here: foreground checker, along with if/else
}
That didn't work either: Everything was just super slow and it ended up force closing, I'm assuming because it ate up all the resources it could.
How do I go about doing this? Main main goal seems to be pretty straightforward... I just want to get the foreground application package name, and just do commands as it changes.
EDIT: I added the following method to MyService:
public int serviceservice() {
boolean running = true;
int showLimit = 20;
boolean doit = true;
/* Get all Tasks available (with limit set). */
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit);
/* Loop through all tasks returned. */
for (ActivityManager.RunningTaskInfo aTask : allTasks)
{
Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName());
if (aTask.baseActivity.getClassName().equals("package"))
running=true;
}
if(running =! true) {
MainActivity defaults = new MainActivity();
defaults.RunAsRoot(commandsdefault);
}
return START_STICKY;
}
And I called serviceservice(); in my OnCreate() and onStart(). It still only runs once. :/
I'll apologize in advance for posting alot of code, this issue has really got me!
I have two Android JUnit tests that are causing me problems. Run each individually and they work fine, but when run together in one go (PasswordEntryActivityTests and then CryptoKeystoreTests) CryptoKeystoreTests hangs indefinitely.
I know it's not just the emulator being slow because each individually finishes in less than a second but it can hang for more than 20 minutes. I also tested it on a real device (Droid Razr) and it does the same thing.
The problematic code is the PasswordEntryActivity.launchNewPasswordActivity(). Removing that function makes everything work fine.
Pausing the function in the debugger while it's hanging says it's in:
MessageQueue.nativePollOnce(int, int) line: not available [native method]
What's going on?
I've copied below:
PasswordEntryActivity
PasswordEntryActivityTests
CryptoManagerKeystoreTests
Please let me know to post any other code you'd like to see.
Thanks!
public class PasswordEntryActivity extends Activity
{
...
private void launchNewPasswordActivity()
{
Intent launchNewPasswordIntent = new Intent(this, NewPasswordActivity.class);
startActivity(launchNewPasswordIntent);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.password_entry_layout);
...
//this code should be LAST in onCreate because it exits the Activity
//CryptoManager.passwordIsRight returns 0 if no password has been set
passwordExists = CryptoManager.passwordIsRight("x", this) != 0;
if(!passwordExists)
launchNewPasswordActivity();
}
}
That Activity's test:
//supposed to make sure the application responds correctly when no password is set
public class PasswordEntryActivityTests extends android.test.ActivityInstrumentationTestCase2< crypnote.controller.main.PasswordEntryActivity>{
protected void setUp() throws Exception
{
passwordEntryActivity = getActivity();
//delete the database if it exists
File file = passwordEntryActivity.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = passwordEntryActivity.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
}
//allows us to access the interface
#UiThreadTest
public void testNoPassword() throws Exception
{
passwordEntryActivity = getActivity();
EditText passwordEntryEditText =
(EditText) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_passwordedittext);
Button unlockButton = (Button) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_unlockbutton);
int passwordResult = CryptoManager.passwordIsRight("x", getActivity());
assertTrue(passwordResult == 0);
//pass a wrong password to the edittext and click the unlock button
passwordEntryEditText.setText("x");
assertTrue(unlockButton.performClick());
//get the foreground activity class name
ActivityManager am = (ActivityManager) passwordEntryActivity.
getSystemService(Context.ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
String foregroundClassName = componentInfo.getShortClassName();
//don't forget the leading '.'
assertTrue(!foregroundClassName.equals(".PasswordEntryActivity"));
}
}
The CryptoKeystoreTests:
public class CryptoKeystoreTests extends android.test.ActivityInstrumentationTestCase2<
crypnote.controller.main.PasswordEntryActivity>
{
public void testKeystore() throws Exception
{
Context context = getActivity();
//delete the database if it exists
File file = context.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = context.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
CryptoManager cryptoManager=null;
String password = CryptoManager.Constants.DEBUG_PASSWORD;
FileInputStream fis=null;
//the cryptomanager will generate a new key and keystore
cryptoManager = new CryptoManager(password, context);
Key CRYPTOKEY = cryptoManager.getKey();
cryptoManager.close();
//initialize KeyStore
KeyStore keystore = KeyStore.getInstance(Constants.KEYSTORE_INSTANCE_TYPE);
fis = context.openFileInput(CryptoManager.Constants.KEYSTORE_PATH);
keystore.load(fis, password.toCharArray());
assertTrue(keystore.containsAlias(Constants.APP_ALIAS));
assertTrue(keystore.isKeyEntry(Constants.APP_ALIAS));
Key key = keystore.getKey(CryptoManager.Constants.APP_ALIAS,
password.toCharArray());
assertTrue(key.getAlgorithm().equals(CryptoManager.Constants.PROVIDER_NAME));
assertTrue(key.getAlgorithm().equals(CRYPTOKEY.getAlgorithm()));
assertTrue(key.getFormat().equals(CRYPTOKEY.getFormat()));
if(fis != null)
fis.close();
}
}
EDIT: NewPasswordActivity.onCreate:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.new_password_layout);
}
It hangs because PasswordEntryActivityTests does not release/finish the resources/UI events that has been addressed/created by itself during its own running lifecycle, more specifically, then newly opened NewPasswordActivity.
PasswordEntryActivityTests starts by testing a creation of PasswordEntryActivity, i.e. getActivity(), which in consequence, based on the condition, launch a second NewPasswordActivity, the newly opened NewPasswordActivity occupy the foreground window and stay forever, it is developer's responsibility to release it properly after you have done your testing.
In instrumentation test, the correct way of detecting/monitoring second activity startup from current activity is to use ActivityMonitor, see the pseudo code below:
// No password result starting a second activity.
public void testNoPassword() {
// register NewPasswordActivity that need to be monitored.
ActivityMonitor activityMonitor = getInstrumentation().addMonitor(NewPasswordActivity.class.getName(), null, false);
// Get current activity, it will start NewPasswordActivity in consequence.
PasswordEntryActivity currentActivity = getActivity();
NewPasswordActivity nextActivity = getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
// NewPasswordActivity is opened and captured.
assertNotNull(nextActivity);
// Don't forget to release/finish NewPasswordActivity after test finish.
nextActivity.finish();
}