I am developing an app for an Android custom build.
This app needs to subscribe to AudioDeviceCallback in Android's AudioManager.
I'm using:
mAudioManager.registerAudioDeviceCallback(new MyDeviceCallback(), null);
where:
private class MyDeviceCallback extends AudioDeviceCallback {
#Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
Log.d(LOG_TAG, "onAudioDevicesAdded(): New devices detected");
updateAuxStatus();
}
#Override
public void onAudioDevicesRemoved(AudioDeviceInfo[] devices) {
Log.d(LOG_TAG, "onAudioDevicesAdded(): devices removed");
updateAuxStatus();
}
private void updateAuxStatus() {
AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
boolean isPluggedIn = false;
for (AudioDeviceInfo device : devices) {
if (device.getType() == AudioDeviceInfo.TYPE_LINE_ANALOG) {
isPluggedIn = true;
}
}
onAuxPluggedInChanged(isPluggedIn);
}
}
This works fine when I run the app with normal user (u0_aXX) but when I run the app as system sharedUser (adding to the Manifest):
android:sharedUserId="android.uid.system"
This callback is being called only after subscribing, but never again. Even when other apps without system user are getting the call normally.
I've traced the call to the AudioManager code and found that postEventFromNative in the AudioPortEventHandler is never being called for my app when it is running as system sharedUser. Since that is a jni call I stopped because I don't fully understand how it works.
What really troubles me is that when running without system sharedUser the same code is working as intended. Is there some restriction to system sharedUser that might be causing this problem?
In the AudioPolicy, registerClient use uid as the key. When the phone booted, system_server or telecom already register notification, if your app run as system user, it will never working.
mNotificationClients.add(uid, notificationClient);
Related
I have a question. Some device has codename.
For example:
Redmi K20Pro has codename "raphael"
Samsung A02S has codename "A02q"
Bluestack 5 (my device need change android codename) has codename: "taimen"
...
So how I can change this codename through adb shell with root access, or terminal on mobile device, or something like this?
Cause I want to make my virtual device as real as possible. Some applications can only use login on previously logged in devices, but cannot log in on the second device except with the intervention of IT support. So I want to create a perfect 2nd instance to sign in on that device, making that device a perfect version of the first device.
private void writeSessionOS(String str) throws Exception {
final boolean isRooted = CommonUtils.isRooted(this.crashlyticsCore.getContext());
writeSessionPartFile(str, SESSION_OS_TAG, new CodedOutputStreamWriteAction() { // from class: com.crashlytics.android.core.CrashlyticsController.21
#Override // com.crashlytics.android.core.CrashlyticsController.CodedOutputStreamWriteAction
public void writeTo(CodedOutputStream codedOutputStream) throws Exception {
SessionProtobufHelper.writeSessionOS(codedOutputStream, Build.VERSION.RELEASE, Build.VERSION.CODENAME, isRooted);
}
});
writeFile(str, "SessionOS.json", new FileOutputStreamWriteAction() { // from class: com.crashlytics.android.core.CrashlyticsController.22
#Override // com.crashlytics.android.core.CrashlyticsController.FileOutputStreamWriteAction
public void writeTo(FileOutputStream fileOutputStream) throws Exception {
fileOutputStream.write(new JSONObject(new HashMap<String, Object>() { // from class: com.crashlytics.android.core.CrashlyticsController.22.1
{
put("version", Build.VERSION.RELEASE);
put("build_version", Build.VERSION.CODENAME);
put("is_rooted", Boolean.valueOf(isRooted));
}
}).toString().getBytes());
}
});
}
Any idea about this?
I write an app which uses three hardware USB-devices.
When I operate with any single device - both events (USB_DEVICE_ATTACHED/USB_DEVICE_DETACHED) fires normally. Not matter how I bind the Receiver - under the manual registration in the code or in the manifest. And not matter how this single device attached - under the HUB or directly to the device.
The problem is: when I connect three device all in one time (by connecting the filled HUB), USB_DEVICE_ATTACHED event fired for all three devices - I receive notification via onNewIntent callback (or standalone Receiver binded via manifest), and do the permission-approve trip.
But on physical removal all devices behind the HUB (by detaching the HUB itself) DETACH event fires not on all devices. It may fired on random single device, or random two devices. But never on all three devices.
As result, for the time UsbManager holds a lot of dead dev-handles of not physically connected devices. At the same time, when I look into /dev/usb/ folder in connecion/disconnection time, device-files appears and removes correctly. As next result, when app is restarted by the some reason, I can not recognize which device is dead and which device is physically present.
The device is ASUS P1801 tablet, OS 4.2.1
As I can see, it is the last firmware from asus (JOP40D.US_epad-10.6.1.22.5-20130715)
For caching purposes, handles of the wrapped-device I pin to the Application singleton (when device appears with the USB_DEVICE_ATTACHED event or app initialisation):
public class HWMountReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Application.getAppContext().isAppReady() && (Application.getAppContext() != null) && (Application.getAppContext().getUsbHWManager() != null)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Application.getAppContext().getUsbHWManager().refreshDevice(device);
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(Application.getAppContext(), 0, new Intent(Application.MED_ONLINE_DEVICE_PERMISSION), 0);
((UsbManager) Application.getAppContext().getSystemService(Context.USB_SERVICE)).requestPermission(device, mPermissionIntent);
}
}
}
The singleton:
private static FirstDevice firstDevice;
private static SecondDevice secondDevice;
private static ThirdDevice thirdDevice;
public void refreshDevice(UsbDevice device) {
HWDevice dev = HWDevicesFactory.newInstance(device);
if (dev instanceof FirstDevice) {
firstDevice = (FirstDevice) dev;
} else if (dev instanceof SecondDevice) {
secondDevice = (SecondDevice) dev;
} else if (dev instanceof ThirdDevice) {
thirdDevice = (ThirdDevice) dev;
}
}
Factory do reInstantination of each device-wrapper:
public static HWDevice newInstance(final UsbDevice device) {
int vendorId = device.getVendorId();
int productId = device.getProductId();
if ((vendorId == FIRST_VENDOR_ID) && (productId == FIRST_PRODUCT_ID)) {
return new FirstDevice(device);
...
Device-Wrapper more specific, because each one is very different. But typicaly it contain cached handles on UsbInterface, UsbDeviceConnection, UsbEndpoints and finally UsbDevice itself.
The main thing - DETACH not fired on random device. Not matter how it was "wrapped" by mine
Is there a probably bug in the ASUS firmware,
-or-
I miss some necessary steps/checks with the device connection
-or-
?
On my Activity :
public class MainActivity extends Activity {
private mDbxAccountManager mDbxAccountManager = null;
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
mDbxAccountManager = DbxAccountManager.getInstance(getApplicationContext(), getString(R.string.dbx_app_key), getString(R.string.dbx_app_secret));
...
}
...
public void buttonOnClick(View view) {
if(mDbxAccountManager.hasLinkedAccount()) {
//Do something
}
else {
mDbxAccountManager.startLink(this, 0);
}
...
}
}
And on my Remote Service :
public class CloudService extends Service {
private mDbxAccountManager mDbxAccountManager = null;
#Override
public void onCreate() {
...
mDbxAccountManager = DbxAccountManager.getInstance(getApplicationContext(), getString(R.string.dbx_app_key), getString(R.string.dbx_app_secret));
if(!mDbxAccountManager.hasLinkedAccount()) {
return;
stopSelf();
}
...
}
}
The result is, after I link my app with dropbox using installed dropbox client, the hasLinkedAccount() on my Activity return true, meanwhile the same code on my Remote Service always return false.
I also check the logcat and it showed that my app already linked with dropbox.
My suspect is that the dropbox API create some SharedPreferences when it successfully link with my app, but my Remote Service can't access that or get a cached version of that SharedPreferences... I don't know...
Please help...
Thank you
Edited :
If I reinstall the app, then the result is as expected and hasLinkedAccount() return true, but if I uninstall and install again which cause clearing the user-data, then I link my app again with Dropbox, then the same strange behaviour appear again.
What I'm doing wrong? I'm turning my head almost 24-hours....
Solved!!!
After trying and trying...
I get conclusion that the Service that runs before the app linked with dropbox will always get DbxAccountManager.hasLinkedAccount() return false.
I try to kill the process by calling Process.killProcess(myservicePid) after I link my app with Dropbox and start the service again and it work.
So... I solved it by not starting the service before the app was linked with dropbox and start the service only if it already linked, because stopSelf() on the service doesn't kill the process.
I think this issue have something to do with the Context getApplicationContext() which is passed to DbxAccountManager.getInstance(), and I don't know why looks like the Context is not updated when the dropbox was link with the app.
Thank you.
I am writing a Spell Check client using the sample code in the SDK as an example. I have the following code (not actual implementation, but an accurate sample representation):
public class HelloSpellChecker implements SpellCheckerSessionListener {
private SpellCheckerSession mSpellCheckService;
private void bindService() {
final TextServicesManager tsm = (TextServicesManager) getSystemService(
Context.TEXT_SERVICES_MANAGER_SERVICE);
mSpellCheckService = tsm.newSpellCheckerSession(null, null, this, true);
}
public void getSuggestions(String word) {
mSpellCheckService.getSuggestions(new TextInfo("tgis"), 3);
}
#Override
public void onGetSentenceSuggestions(final SentenceSuggestionsInfo[] arg0) {
Log.d(TAG, "onGetSentenceSuggestions");
// Process suggestions
}
}
What I want to know is will onGetSentenceSuggestions only be fired when my application calls getSuggestions, or will it be fired any time the system service receives a request to getSuggestions?
If it is the latter, what is the best way to ensure my app only processes suggestions which it requested?
I would say Android system service listener is localized through the session in this case.
onGetSentenceSuggestions method is fired by any request to getSuggestions method. However, you don't have to worry about processing suggestions which your app requested since the spellchecker session takes care of it. Your app only gets the suggestions requested by the session your app created to interact with the spell checker service.
Hope this helps.
References:
http://developer.android.com/reference/android/view/textservice/SpellCheckerSession.html
http://developer.android.com/guide/topics/text/spell-checker-framework.html
I want to make Radio Web App Android-browser-based.
The key function for my Web App is continuously playing music-list
(mp3 files) ...
JavaScript Code is simple ...
And it works well in PC Browser, iOS safari, and Android Dolphin
Browser (3rd party browser)...
var audioPlayer = new Audio();
audioPlayer.addEventListener('ended', nextSong, false);
function nextSong() {
audioPlayer.src = nextMusic_src;
}
But. in Android Default Browser,
when android is in background mode (Home Screen mode & LCD-off Sleep
mode),
Android Browser's onPause() prevent "ended" event & execution of
nextSong().
So, my web app can play only one music.... and does not work any
more.....
Android Browser's onPause() source code is like this ...
BrowserActivity.java
public class BrowserActivity extends Activity
{
private Controller mController;
// ...
#Override
protected void onPause() {
if (mController != null) {
mController.onPause(); // <<==== here
}
super.onPause();
}
}
Controller.java
public class Controller implements WebViewController, UiController {
protected void onPause() {
// ...
mActivityPaused = true;
// ...
mUi.onPause();
mNetworkHandler.onPause(); // <<==== here
WebView.disablePlatformNotifications(); // <<====here
}
}
NetworkStateHandler.java
public class NetworkStateHandler {
// ...
void onPause() {
// unregister network state listener
mActivity.unregisterReceiver(mNetworkStateIntentReceiver); // <<==== here
}
}
Is there any browser policy for preventing event in background
mode....?
If not, how can I notice this report to the Google developer for
requesting background music play with web app...?
I consider not WebView based web-app (Hybrid) but only browser-based
web-app...
thank you...
Nohyun Kwak
Droid's ended event doesn't fire consistently. It's fixed in ICS, I hear. But Gingerbread and prior have the issue.
Instead of listening for .ended, can you listen for .timeupdate and in that handler, see if the time is the end of the song? That may solve your issue.