I am trying to create extension to detect if user click on volume up or down and set it to event.
I found this code
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
volumeButtonListener.onVolumeUp();
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
volumeButtonListener.onVolumeDown();
return true;
}
return super.onKeyDown(keyCode, event);
}
But I think app inventor doesn't have onKeyDown
inside it...
do you have any idea?
Two years ago I had made an extension to listen to key events, not sure where it is.
It is not directly possible at all, you need to do some special reflection operations. The code's somewhere lying around in my old hard drive... that i dont currently have access to it until three days.
Edit: However if you are primarily concerned about listening to volume changes, there are other Android APIs available
1 Like
JEWEL
October 10, 2024, 3:25pm
3
I'm using the below code into my projects and it's working fine for me.
Create the custom listener class
class VolumeButtonListener extends ContentObserver {
int previousVolume;
public VolumeButtonListener(Handler handler) {
super(handler);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta = previousVolume - currentVolume;
if (delta > 0) {
previousVolume = currentVolume;
// Volume down button is clicked
} else if (delta < 0) {
previousVolume = currentVolume;
// Volume up button is clicked
}
}
}
Declare and Initialize the variable
// Declare the variable for global use
private VolumeButtonListener volumeListener;
// Initialize the variable
volumeListener = new VolumeButtonListener(new Handler(Looper.getMainLooper()));
Register the listener class as ContentObserver
// Register the VolumeButtonListener class as ContentObserver
context.getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, volumeListener);
Remove the VolumeButtonListener class from ContentObserver on the Activity destroy
container.$form().registerForOnDestroy(new OnDestroyListener() {
@Override
public void onDestroy() {
context.getContentResolver().unregisterContentObserver(volumeListener);
}
});
Hope it helps
2 Likes
Hope you can share code ASAP.
like what?
i tested it, it is not work for me.
AIX:
me.aemo.volumedetector.aix (7.2 KB)
AIA:
VolumeTrackerEx.aia (9.5 KB)
JEWEL
October 10, 2024, 5:18pm
6
JEWEL:
VolumeButtonListener
VolumeButtonListener use this class as inner class.
My Code:
VolumeTracker.java
package me.aemo.volumedetector.lib;
import android.content.Context;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.os.Handler;
public class VolumeTracker extends ContentObserver {
private final Context context;
private final VolumeListener listener;
private int previousVolume;
public VolumeTracker(Handler handler, Context context, VolumeListener listener) {
super(handler);
this.context = context;
this.listener = listener;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta = previousVolume - currentVolume;
if (delta > 0) {
previousVolume = currentVolume;
if (listener != null) listener.onVolumeUp();
} else if (delta < 0) {
previousVolume = currentVolume;
if (listener != null) listener.onVolumeDown();
}
}
}
VolumeListener.java
package me.aemo.volumedetector.lib;
public interface VolumeListener {
void onVolumeUp();
void onVolumeDown();
}
Extension Code
VolumeDetector.java
public class VolumeDetector extends AndroidNonvisibleComponent
implements VolumeListener, OnDestroyListener {
private static final String TAG = "VolumeDetector";
private VolumeTracker volumeTracker;
private final Context context;
public VolumeDetector(ComponentContainer container){
super(container.$form());
this.context = container.$context();
}
@SimpleFunction
public void Initialize(){
if (volumeTracker == null){
this.volumeTracker = new VolumeTracker(new Handler(Looper.getMainLooper()), context, this);
}
}
@SimpleFunction
public void StartListener(){
if (volumeTracker != null){
context.getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, volumeTracker);
}
}
@SimpleFunction
public void StopListener(){
if (volumeTracker != null){
context.getContentResolver().unregisterContentObserver(volumeTracker);
}
}
@Override
public void onVolumeUp() {
form.runOnUiThread(new Runnable() {
@Override
public void run() {
OnVolumeUp();
}
});
}
@SimpleEvent
public void OnVolumeUp() {
EventDispatcher.dispatchEvent(this,"OnVolumeUp");
}
@Override
public void onVolumeDown() {
form.runOnUiThread(new Runnable() {
@Override
public void run() {
OnVolumeDown();
}
});
}
@SimpleEvent
public void OnVolumeDown() {
EventDispatcher.dispatchEvent(this,"OnVolumeDown");
}
@Override
public void onDestroy() {
context.getContentResolver().unregisterContentObserver(volumeTracker);
}
}
JEWEL
October 10, 2024, 5:25pm
9
No, you're not following my instructions.
JEWEL
October 10, 2024, 5:45pm
11
Please try this code:
package me.aemo.volumedetector;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.OnDestroyListener;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import android.content.Context;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings.System;
@DesignerComponent(version = 2, versionName = "1.0", description = "Developed by Mahmoud Hooda by Fast.", iconName = "icon.png")
public class VolumeDetector extends AndroidNonvisibleComponent {
private final Context context;
private VolumeButtonListener volumeListener;
public VolumeDetector(ComponentContainer container) {
super(container.$form());
context = container.$context().getApplicationContext();
volumeListener = new VolumeButtonListener(new Handler(Looper.getMainLooper()));
container.$form().registerForOnDestroy(new OnDestroyListener() {
@Override
public void onDestroy() {
StopListening();
}
});
}
@SimpleFunction(description = "Start listening the volumn button press.")
public void StartListening() {
context.getContentResolver().registerContentObserver(System.CONTENT_URI, true, volumeListener);
}
@SimpleFunction(description = "Stop listening the volumn button press.")
public void StopListening() {
if (volumeListener != null) {
context.getContentResolver().unregisterContentObserver(volumeListener);
}
}
@SimpleEvent(description = "The volume up button is pressed.")
public void VolumeUpPressed() {
EventDispatcher.dispatchEvent(this, "VolumeUpPressed");
}
@SimpleEvent(description = "The volume down button is pressed.")
public void VolumeDownPressed() {
EventDispatcher.dispatchEvent(this, "VolumeDownPressed");
}
// Inner class to listen the volume button press
class VolumeButtonListener extends ContentObserver {
int previousVolume;
public VolumeButtonListener(Handler handler) {
super(handler);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta = previousVolume - currentVolume;
if (delta > 0) {
previousVolume = currentVolume;
VolumeDownPressed();
} else if (delta < 0) {
previousVolume = currentVolume;
VolumeUpPressed();
}
}
}
}
me.aemo.volumedetector.aix (6.5 KB)
1 Like
JEWEL
October 10, 2024, 6:09pm
13
I've just tested it on Kodular and it's working there on Companion and APK. You might need to export the apk from AI2 for testing. I'm not sure. You might give a try.
1 Like
JEWEL
October 10, 2024, 6:17pm
15
VolumeListener.aia (3.6 MB) (Rename it as .aia to .apk)
And this apk is also working. It's exported from AI2.
1 Like
JEWEL
October 10, 2024, 6:18pm
16
Here is the aia files.
VolumeListener.aia (8.9 KB) (AI2)
AdmobBlocks.aia (26.6 KB) (Kodular)
hhhhhhhhhh
i know now why it is not work,
It only works when you raise or lower the Media
volume.
and my device automatically raise or lower volume of Ringtone
Edit: i mean those
Can you edit the code to work on all volume types @JEWEL
JEWEL
October 10, 2024, 6:37pm
19
You mean to listen the specific type of volume like: Ringtone, Media, Notification, System?
1 Like
i don't need to create listener for specific type just on volume up or down.
i don't care if it is Ringtone, Media, Notification, System