Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
Fixed bug 18405121: Remove RECORD_AUDIO permission requirement for AT…
…V Leanback sample

Change-Id: I0fb0b3ccd69ba809ae74ffd07f3bab0ad2199c99
  • Loading branch information
shawngit committed Mar 5, 2015
1 parent 1c56d47 commit 76022fd0126b17a82486af9613159262eccef852
@@ -26,9 +26,7 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<!-- The android.hardware.microphone feature requirement is implied by the RECORD_AUDIO permission but isn't available on every Android TV devices. -->
<uses-feature
android:name="android.hardware.microphone"
android:required="false" />
@@ -94,9 +92,11 @@
android:authorities="com.example.android.tvleanback"
android:exported="true" />

<provider android:name=".recommendation.RecommendationBuilder$RecommendationBackgroundContentProvider"
<provider
android:name=".recommendation.RecommendationBuilder$RecommendationBackgroundContentProvider"
android:authorities="com.example.android.tvleanback.recommendation"
android:exported="true" />

<receiver
android:name=".recommendation.BootupActivity"
android:enabled="true"
@@ -17,6 +17,8 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v17.leanback.widget.SpeechRecognitionCallback;
import android.util.Log;

import com.example.android.tvleanback.R;

@@ -27,10 +29,42 @@
/**
* Called when the activity is first created.
*/

private static final String TAG = "SearchActivity";
private static boolean DEBUG = true;
/**
* SpeechRecognitionCallback is not required and if not provided recognition will be handled
* using internal speech recognizer, in which case you must have RECORD_AUDIO permission
*/
private static final int REQUEST_SPEECH = 1;
private SearchFragment mFragment;
private SpeechRecognitionCallback mSpeechRecognitionCallback;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);

mFragment = (SearchFragment) getFragmentManager().findFragmentById(R.id.search_fragment);

mSpeechRecognitionCallback = new SpeechRecognitionCallback() {
@Override
public void recognizeSpeech() {
if (DEBUG) Log.v(TAG, "recognizeSpeech");
startActivityForResult(mFragment.getRecognizerIntent(), REQUEST_SPEECH);
}
};
mFragment.setSpeechRecognitionCallback(mSpeechRecognitionCallback);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (DEBUG) Log.v(TAG, "onActivityResult requestCode=" + requestCode +
" resultCode=" + resultCode +
" data=" + data);
if (requestCode == REQUEST_SPEECH && resultCode == RESULT_OK) {
mFragment.setSearchQuery(data, true);
}
}

@Override
@@ -19,13 +19,18 @@
import android.os.Handler;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.HeaderItem;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
import android.support.v17.leanback.widget.ObjectAdapter;
import android.support.v17.leanback.widget.OnItemClickedListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v4.app.ActivityOptionsCompat;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.example.android.tvleanback.R;
import com.example.android.tvleanback.data.VideoProvider;
@@ -43,19 +48,20 @@
public class SearchFragment extends android.support.v17.leanback.app.SearchFragment
implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {
private static final String TAG = "SearchFragment";
private static final int SEARCH_DELAY_MS = 300;
private static final int SEARCH_DELAY_MS = 1000;

private ArrayObjectAdapter mRowsAdapter;
private Handler mHandler = new Handler();
private SearchRunnable mDelayedLoad;
private String mQuery;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
setSearchResultProvider(this);
setOnItemClickedListener(getDefaultItemClickedListener());
setOnItemViewClickedListener(new ItemViewClickedListener());
mDelayedLoad = new SearchRunnable();
}

@@ -64,61 +70,49 @@ public ObjectAdapter getResultsAdapter() {
return mRowsAdapter;
}

private void queryByWords(String words) {
mRowsAdapter.clear();
if (!TextUtils.isEmpty(words)) {
mDelayedLoad.setSearchQuery(words);
mHandler.removeCallbacks(mDelayedLoad);
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
}
}

@Override
public boolean onQueryTextChange(String newQuery) {
Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
queryByWords(newQuery);
loadQuery(newQuery);
return true;
}

@Override
public boolean onQueryTextSubmit(String query) {
Log.i(TAG, String.format("Search Query Text Submit %s", query));
queryByWords(query);
loadQuery(query);
return true;
}

private void loadQuery(String query) {
mQuery = query;
mRowsAdapter.clear();
mHandler.removeCallbacks(mDelayedLoad);
if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
mDelayedLoad.setSearchQuery(query);
mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
}
}

private void loadRows(String query) {
HashMap<String, List<Movie>> movies = VideoProvider.getMovieList();
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
for (Map.Entry<String, List<Movie>> entry : movies.entrySet()) {
for (Movie movie : entry.getValue()) {
if (movie.getTitle().toLowerCase(Locale.ENGLISH)
.indexOf(query.toLowerCase(Locale.ENGLISH)) >= 0
.contains(query.toLowerCase(Locale.ENGLISH))
|| movie.getDescription().toLowerCase(Locale.ENGLISH)
.indexOf(query.toLowerCase(Locale.ENGLISH)) >= 0) {
.contains(query.toLowerCase(Locale.ENGLISH))) {
listRowAdapter.add(movie);
}
}
}
HeaderItem header = new HeaderItem(0, getResources().getString(R.string.search_results),
HeaderItem header = new HeaderItem(0, getResources().getString(R.string.search_results)
+ " '" + mQuery + "'",
null);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}

protected OnItemClickedListener getDefaultItemClickedListener() {
return new OnItemClickedListener() {
@Override
public void onItemClicked(Object item, Row row) {
if (item instanceof Movie) {
Movie movie = (Movie) item;
Intent intent = new Intent(getActivity(), MovieDetailsActivity.class);
intent.putExtra(MovieDetailsActivity.MOVIE, movie);
startActivity(intent);
}
}
};
}

private class SearchRunnable implements Runnable {

private volatile String searchQuery;
@@ -134,4 +128,29 @@ public void setSearchQuery(String value) {
this.searchQuery = value;
}
}

private final class ItemViewClickedListener implements OnItemViewClickedListener {
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {

if (item instanceof Movie) {
Movie movie = (Movie) item;
Log.d(TAG, "Movie: " + movie.toString());
Intent intent = new Intent(getActivity(), MovieDetailsActivity.class);
intent.putExtra(MovieDetailsActivity.MOVIE, movie);

Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
getActivity(),
((ImageCardView) itemViewHolder.view).getMainImageView(),
MovieDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
getActivity().startActivity(intent, bundle);
} else {
Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT)
.show();
}
}
}


}

0 comments on commit 76022fd

Please sign in to comment.