Merge "Add voice interaction support to ResolverActivity/ChooserActivity" into mnc-dev
This commit is contained in:
@@ -100,6 +100,10 @@ public class ChooserActivity extends ResolverActivity {
|
|||||||
mChooserListAdapter.addServiceResults(sri.originalTarget, sri.resultTargets);
|
mChooserListAdapter.addServiceResults(sri.originalTarget, sri.resultTargets);
|
||||||
unbindService(sri.connection);
|
unbindService(sri.connection);
|
||||||
mServiceConnections.remove(sri.connection);
|
mServiceConnections.remove(sri.connection);
|
||||||
|
if (mServiceConnections.isEmpty()) {
|
||||||
|
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
|
||||||
|
sendVoiceChoicesIfNeeded();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT:
|
case CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT:
|
||||||
@@ -107,6 +111,7 @@ public class ChooserActivity extends ResolverActivity {
|
|||||||
Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
|
Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
|
||||||
}
|
}
|
||||||
unbindRemainingServices();
|
unbindRemainingServices();
|
||||||
|
sendVoiceChoicesIfNeeded();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -384,6 +389,8 @@ public class ChooserActivity extends ResolverActivity {
|
|||||||
+ WATCHDOG_TIMEOUT_MILLIS + "ms");
|
+ WATCHDOG_TIMEOUT_MILLIS + "ms");
|
||||||
mChooserHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
|
mChooserHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
|
||||||
WATCHDOG_TIMEOUT_MILLIS);
|
WATCHDOG_TIMEOUT_MILLIS);
|
||||||
|
} else {
|
||||||
|
sendVoiceChoicesIfNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +425,10 @@ public class ChooserActivity extends ResolverActivity {
|
|||||||
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
|
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onSetupVoiceInteraction() {
|
||||||
|
// Do nothing. We'll send the voice stuff ourselves.
|
||||||
|
}
|
||||||
|
|
||||||
void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
|
void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
|
||||||
if (mRefinementResultReceiver != null) {
|
if (mRefinementResultReceiver != null) {
|
||||||
mRefinementResultReceiver.destroy();
|
mRefinementResultReceiver.destroy();
|
||||||
@@ -956,6 +967,10 @@ public class ChooserActivity extends ResolverActivity {
|
|||||||
if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
|
if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
|
||||||
unbindService(this);
|
unbindService(this);
|
||||||
mServiceConnections.remove(this);
|
mServiceConnections.remove(this);
|
||||||
|
if (mServiceConnections.isEmpty()) {
|
||||||
|
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
|
||||||
|
sendVoiceChoicesIfNeeded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,10 +16,17 @@
|
|||||||
|
|
||||||
package com.android.internal.app;
|
package com.android.internal.app;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
|
import android.app.VoiceInteractor;
|
||||||
|
import android.app.VoiceInteractor.PickOptionRequest;
|
||||||
|
import android.app.VoiceInteractor.PickOptionRequest.Option;
|
||||||
|
import android.app.VoiceInteractor.Prompt;
|
||||||
|
import android.app.VoiceInteractor.Request;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.service.chooser.ChooserTarget;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
@@ -96,6 +103,7 @@ public class ResolverActivity extends Activity {
|
|||||||
private int mProfileSwitchMessageId = -1;
|
private int mProfileSwitchMessageId = -1;
|
||||||
private final ArrayList<Intent> mIntents = new ArrayList<>();
|
private final ArrayList<Intent> mIntents = new ArrayList<>();
|
||||||
private ResolverComparator mResolverComparator;
|
private ResolverComparator mResolverComparator;
|
||||||
|
private PickTargetOptionRequest mPickOptionRequest;
|
||||||
|
|
||||||
private boolean mRegistered;
|
private boolean mRegistered;
|
||||||
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
||||||
@@ -242,6 +250,9 @@ public class ResolverActivity extends Activity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (isVoiceInteraction()) {
|
||||||
|
rdl.setCollapsed(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title == null) {
|
if (title == null) {
|
||||||
@@ -313,6 +324,39 @@ public class ResolverActivity extends Activity {
|
|||||||
});
|
});
|
||||||
bindProfileView();
|
bindProfileView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isVoiceInteraction()) {
|
||||||
|
onSetupVoiceInteraction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform any initialization needed for voice interaction.
|
||||||
|
*/
|
||||||
|
void onSetupVoiceInteraction() {
|
||||||
|
// Do it right now. Subclasses may delay this and send it later.
|
||||||
|
sendVoiceChoicesIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendVoiceChoicesIfNeeded() {
|
||||||
|
if (!isVoiceInteraction()) {
|
||||||
|
// Clearly not needed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final Option[] options = new Option[mAdapter.getCount()];
|
||||||
|
for (int i = 0, N = options.length; i < N; i++) {
|
||||||
|
options[i] = optionForChooserTarget(mAdapter.getItem(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPickOptionRequest = new PickTargetOptionRequest(
|
||||||
|
new Prompt(getTitle()), options, null);
|
||||||
|
getVoiceInteractor().submitRequest(mPickOptionRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
Option optionForChooserTarget(TargetInfo target, int index) {
|
||||||
|
return new Option(target.getDisplayLabel(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void setAdditionalTargets(Intent[] intents) {
|
protected final void setAdditionalTargets(Intent[] intents) {
|
||||||
@@ -472,6 +516,14 @@ public class ResolverActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (!isChangingConfigurations() && mPickOptionRequest != null) {
|
||||||
|
mPickOptionRequest.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
@@ -510,16 +562,12 @@ public class ResolverActivity extends Activity {
|
|||||||
try {
|
try {
|
||||||
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(
|
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(
|
||||||
resolveInfo.activityInfo.packageName, 0 /* default flags */);
|
resolveInfo.activityInfo.packageName, 0 /* default flags */);
|
||||||
return versionNumberAtLeastL(appInfo.targetSdkVersion);
|
return appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean versionNumberAtLeastL(int versionNumber) {
|
|
||||||
return versionNumber >= Build.VERSION_CODES.LOLLIPOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
|
private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
|
||||||
boolean filtered) {
|
boolean filtered) {
|
||||||
boolean enabled = false;
|
boolean enabled = false;
|
||||||
@@ -1644,4 +1692,39 @@ public class ResolverActivity extends Activity {
|
|||||||
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
|
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class PickTargetOptionRequest extends PickOptionRequest {
|
||||||
|
public PickTargetOptionRequest(@Nullable Prompt prompt, Option[] options,
|
||||||
|
@Nullable Bundle extras) {
|
||||||
|
super(prompt, options, extras);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel() {
|
||||||
|
super.onCancel();
|
||||||
|
final ResolverActivity ra = (ResolverActivity) getActivity();
|
||||||
|
if (ra != null) {
|
||||||
|
ra.mPickOptionRequest = null;
|
||||||
|
ra.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
|
||||||
|
super.onPickOptionResult(finished, selections, result);
|
||||||
|
if (selections.length != 1) {
|
||||||
|
// TODO In a better world we would filter the UI presented here and let the
|
||||||
|
// user refine. Maybe later.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ResolverActivity ra = (ResolverActivity) getActivity();
|
||||||
|
if (ra != null) {
|
||||||
|
final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex());
|
||||||
|
if (ra.onTargetSelected(ti, false)) {
|
||||||
|
ra.mPickOptionRequest = null;
|
||||||
|
ra.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,14 @@ public class ResolverDrawerLayout extends ViewGroup {
|
|||||||
return mCollapseOffset > 0;
|
return mCollapseOffset > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCollapsed(boolean collapsed) {
|
||||||
|
if (!isLaidOut()) {
|
||||||
|
mOpenOnLayout = collapsed;
|
||||||
|
} else {
|
||||||
|
smoothScrollTo(collapsed ? mCollapsibleHeight : 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isMoving() {
|
private boolean isMoving() {
|
||||||
return mIsDragging || !mScroller.isFinished();
|
return mIsDragging || !mScroller.isFinished();
|
||||||
}
|
}
|
||||||
@@ -575,7 +583,13 @@ public class ResolverDrawerLayout extends ViewGroup {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
||||||
if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
|
if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
|
||||||
smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
|
if (mOnDismissedListener != null
|
||||||
|
&& velocityY < 0 && mCollapseOffset > mCollapsibleHeight) {
|
||||||
|
smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, velocityY);
|
||||||
|
mDismissOnScrollerFinished = true;
|
||||||
|
} else {
|
||||||
|
smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -2457,6 +2457,7 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.CHOOSER" />
|
<action android:name="android.intent.action.CHOOSER" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.VOICE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.android.internal.app.IntentForwarderActivity"
|
<activity android:name="com.android.internal.app.IntentForwarderActivity"
|
||||||
|
|||||||
Reference in New Issue
Block a user