| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.musicfx; |
| |
| import android.app.Activity; |
| import android.app.IntentService; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.SharedPreferences.Editor; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.media.audiofx.AudioEffect; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.util.Log; |
| |
| import java.util.List; |
| |
| /** |
| * Provide backwards compatibility for existing control panels. |
| * There are two major parts to this: |
| * - a BroadcastReceiver that listens for installed or removed packages, and |
| * enables or disables control panel receivers as needed to ensure that only |
| * one control panel package will receive the broadcasts that applications end |
| * - a high priority control panel activity that redirects to the currently |
| * selected control panel activity |
| * |
| */ |
| public class Compatibility { |
| |
| private final static String TAG = "MusicFXCompat"; |
| // run "setprop log.tag.MusicFXCompat DEBUG" to turn on logging |
| private final static boolean LOG = Log.isLoggable(TAG, Log.DEBUG); |
| |
| |
| /** |
| * This activity has an intent filter with the highest possible priority, so |
| * it will always be chosen. It then looks up the correct control panel to |
| * use and launches that. |
| */ |
| public static class Redirector extends Activity { |
| |
| @Override |
| public void onCreate(final Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| log("Compatibility Activity called from " + getCallingPackage()); |
| Intent i = new Intent(getIntent()); |
| i.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); |
| SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE); |
| String defPackage = pref.getString("defaultpanelpackage", null); |
| String defName = pref.getString("defaultpanelname", null); |
| log("read " + defPackage + "/" + defName + " as default"); |
| if (defPackage == null || defName == null) { |
| Log.e(TAG, "no default set!"); |
| // use the built-in panel |
| i.setComponent(new ComponentName(this, ActivityMusic.class)); |
| // also save it as the default |
| Intent updateIntent = new Intent(this, Service.class); |
| updateIntent.putExtra("defPackage", getPackageName()); |
| updateIntent.putExtra("defName", ActivityMusic.class.getName()); |
| startService(updateIntent); |
| } else { |
| i.setComponent(new ComponentName(defPackage, defName)); |
| } |
| startActivity(i); |
| finish(); |
| } |
| } |
| |
| /** |
| * This BroadcastReceiver responds to BOOT_COMPLETED, PACKAGE_ADDED, |
| * PACKAGE_REPLACED and PACKAGE_REMOVED intents. When run, it checks |
| * to see whether the active control panel needs to be updated: |
| * - if there is no default, it picks one |
| * - if a new control panel is installed, it becomes the default |
| * It then enables the open/close receivers in the active control panel, |
| * and disables them in the others. |
| */ |
| public static class Receiver extends BroadcastReceiver { |
| |
| @Override |
| public void onReceive(final Context context, final Intent intent) { |
| |
| log("received"); |
| Intent updateIntent = new Intent(context, Service.class); |
| updateIntent.putExtra("reason", intent); |
| context.startService(updateIntent); |
| } |
| } |
| |
| public static class Service extends IntentService { |
| |
| PackageManager mPackageManager; |
| |
| public Service() { |
| super("CompatibilityService"); |
| } |
| |
| @Override |
| protected void onHandleIntent(final Intent intent) { |
| log("handleintent"); |
| if (mPackageManager == null) { |
| mPackageManager = getPackageManager(); |
| } |
| |
| String defPackage = intent.getStringExtra("defPackage"); |
| String defName = intent.getStringExtra("defName"); |
| if (defPackage != null && defName != null) { |
| setDefault(defPackage, defName); |
| return; |
| } |
| |
| Intent packageIntent = intent.getParcelableExtra("reason"); |
| Bundle b = packageIntent.getExtras(); |
| if (b != null) b.size(); |
| log("intentservice saw: " + packageIntent + " " + b); |
| // TODO, be smarter about package upgrades (which results in three |
| // broadcasts: removed, added, replaced) |
| Uri packageUri = packageIntent.getData(); |
| String updatedPackage = null; |
| if (packageUri != null) { |
| updatedPackage = packageUri.toString().substring(8); |
| pickDefaultControlPanel(updatedPackage); |
| } |
| } |
| |
| private void pickDefaultControlPanel(String updatedPackage) { |
| |
| ResolveInfo defPanel = null; |
| ResolveInfo otherPanel = null; |
| ResolveInfo thisPanel = null; |
| Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL); |
| List<ResolveInfo> ris = mPackageManager.queryIntentActivities(i, PackageManager.GET_DISABLED_COMPONENTS); |
| log("found: " + ris.size()); |
| SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE); |
| String savedDefPackage = pref.getString("defaultpanelpackage", null); |
| String savedDefName = pref.getString("defaultpanelname", null); |
| log("saved default: " + savedDefName); |
| for (ResolveInfo foo: ris) { |
| if (foo.activityInfo.name.equals(Compatibility.Redirector.class.getName())) { |
| log("skipping " + foo); |
| continue; |
| } |
| log("considering " + foo); |
| if (foo.activityInfo.name.equals(savedDefName) && |
| foo.activityInfo.packageName.equals(savedDefPackage) && |
| foo.activityInfo.enabled) { |
| log("default: " + savedDefName); |
| defPanel = foo; |
| break; |
| } else if (foo.activityInfo.packageName.equals(updatedPackage)) { |
| log("choosing newly installed package " + updatedPackage); |
| otherPanel = foo; |
| } else if (otherPanel == null && !foo.activityInfo.packageName.equals(getPackageName())) { |
| otherPanel = foo; |
| } else { |
| thisPanel = foo; |
| } |
| } |
| |
| if (defPanel == null) { |
| // pick a default control panel |
| if (otherPanel == null) { |
| if (thisPanel == null) { |
| Log.e(TAG, "No control panels found!"); |
| return; |
| } |
| otherPanel = thisPanel; |
| } |
| defPanel = otherPanel; |
| } |
| |
| // Now that we have selected a default control panel activity, ensure |
| // that the broadcast receiver(s) in that same package are enabled, |
| // and the ones in the other packages are disabled. |
| String defPackage = defPanel.activityInfo.packageName; |
| String defName = defPanel.activityInfo.name; |
| setDefault(defPackage, defName); |
| } |
| |
| private void setDefault(String defPackage, String defName) { |
| Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); |
| List<ResolveInfo> ris = mPackageManager.queryBroadcastReceivers(i, PackageManager.GET_DISABLED_COMPONENTS); |
| setupReceivers(ris, defPackage); |
| // The open and close receivers are likely the same, but they may not be. |
| i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); |
| ris = mPackageManager.queryBroadcastReceivers(i, PackageManager.GET_DISABLED_COMPONENTS); |
| setupReceivers(ris, defPackage); |
| |
| // Write the selected default to the prefs so that the Redirector activity |
| // knows which one to use. |
| SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE); |
| Editor ed = pref.edit(); |
| ed.putString("defaultpanelpackage", defPackage); |
| ed.putString("defaultpanelname", defName); |
| ed.commit(); |
| log("wrote " + defPackage + "/" + defName + " as default"); |
| } |
| |
| private void setupReceivers(List<ResolveInfo> ris, String defPackage) { |
| // TODO - we may need to keep track of active sessions and send "open session" |
| // broadcast to newly enabled receivers, while sending "close session" to |
| // receivers that are about to be disabled. We could also consider just |
| // killing the process hosting the disabled components. |
| for (ResolveInfo foo: ris) { |
| ComponentName comp = new ComponentName(foo.activityInfo.packageName, foo.activityInfo.name); |
| if (foo.activityInfo.packageName.equals(defPackage)) { |
| log("enabling receiver " + foo); |
| mPackageManager.setComponentEnabledSetting(comp, |
| PackageManager.COMPONENT_ENABLED_STATE_ENABLED, |
| PackageManager.DONT_KILL_APP); |
| } else { |
| log("disabling receiver " + foo); |
| mPackageManager.setComponentEnabledSetting(comp, |
| PackageManager.COMPONENT_ENABLED_STATE_DISABLED, |
| PackageManager.DONT_KILL_APP); |
| } |
| } |
| } |
| } |
| |
| private static void log(String out) { |
| if (LOG) { |
| Log.d(TAG, out); |
| } |
| } |
| } |