3

I have seen multiple questions on SO that say it is impossible to see when another app wants to use the microphone (Unable to access microphone when another app is using it in Android). However, I know it is possible because Shazam has an "Auto" function that allows the exact functionality I want: to continuously listen to audio when other apps are not using the microphone.

Currently, when I use my app and use an app like Snapchat, I am unable to record a video with audio because Snapchat does not take the mic over. However, as I said before, in this case Shazam's Auto feature works fine.

So how do I listen for when other apps want to use the mic? I am fine using something that is a "hack" as long as it does not require rooting the phone or similar.

EDIT: Shazam never had this functionality, their app fails to relinquish the mic to other applications while it is running.

HaydenKai
  • 871
  • 7
  • 31

1 Answers1

3

This is currently the best solution I have. There is no way to listen for other applications requesting the microphone, so I created a UsageStats checker that runs every 3 seconds to see if the currently open app has the ability to request audio. Please let me know if you have something better or make improvements to this.

Note: You must add the permissions to the app manifest:

<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />

    AppOpsManager appOps = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
    int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
            android.os.Process.myUid(), getPackageName());

    if (mode != AppOpsManager.MODE_ALLOWED) {
        Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        startActivity(intent);
    }

    if (otherAppAudioTimer != null) {
        otherAppAudioTimer.cancel();
    }

    otherAppAudioTimer = new Timer();
    otherAppAudioTimer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            UsageStatsManager usm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
            long now = System.currentTimeMillis();
            final List<UsageStats> queryUsageStats = usm.queryUsageStats(UsageStatsManager.INTERVAL_YEARLY, now - (1000 * 60 * 60), now);
            if (queryUsageStats != null && queryUsageStats.size() > 0) {
                SortedMap<Long, UsageStats> mySortedMap = new TreeMap<>();
                for (UsageStats usageStats : queryUsageStats) {
                    mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
                }
                if (!mySortedMap.isEmpty()) {
                    String currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
                    boolean hasRecordAudio = getPackageManager()
                            .checkPermission(Manifest.permission.RECORD_AUDIO, currentApp)
                            == PackageManager.PERMISSION_GRANTED;

                    if (getApplicationContext().getPackageName().equals(currentApp)) {
                        Log.e("hasAudio", "Current app is self");
                        return;
                    }


                    if (hasRecordAudio) {
                        //the current app can record audio
                    } else {
                        //the current app cannot record audio
                    }

                }
            }
        }
    }, 0, 3000);
HaydenKai
  • 871
  • 7
  • 31
  • From [the docs](https://developer.android.com/reference/android/app/usage/UsageStatsManager.html): `PACKAGE_USAGE_STATS` . . . is a system-level permission and will not be granted to third-party apps. However . . . the user of the device can grant permission through the Settings application. – Kevin Krumwiede Apr 26 '17 at 01:20
  • @KevinKrumwiede yes, it is not implictly granted by Android, but in my code the Intent code makes a request to allow the permission if the user has not already. This is also why I need to use the ignore in the permission – HaydenKai Apr 26 '17 at 05:21
  • The docs for [`ACTION_USAGE_ACCESS_SETTINGS`](https://developer.android.com/reference/android/provider/Settings.html#ACTION_USAGE_ACCESS_SETTINGS) say that it may not be available on all devices. In the early days of Lollipop, I read that major manufacturers including Samsung and LG had removed it from many of their devices. Have you run into problems with this? – Kevin Krumwiede Apr 26 '17 at 06:28
  • @KevinKrumwiede no, but this is a "hack", there are many things wrong with the method I am using but it is the best way to achieve what I want. When Android offers something that is better I will use it/update this (Aka broadcast listeners just like the `AudioManager`) – HaydenKai Apr 26 '17 at 17:27
  • But why check if the current app has the record audio permission? Was it not already granted by the user? Why is that different from Context.checkSelfPermission()? – Edw590 Mar 02 '23 at 18:35