238 lines
8.9 KiB
Java
238 lines
8.9 KiB
Java
/*
|
|
* Copyright (c) 2014 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.liskovsoft.smartyoutubetv2.tv.ui.search;
|
|
|
|
import android.Manifest;
|
|
import android.app.Activity;
|
|
import android.content.ActivityNotFoundException;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.PackageManager;
|
|
import android.database.Cursor;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import androidx.leanback.app.SearchSupportFragment;
|
|
import androidx.leanback.widget.ArrayObjectAdapter;
|
|
import androidx.leanback.widget.CursorObjectAdapter;
|
|
import androidx.leanback.widget.HeaderItem;
|
|
import androidx.leanback.widget.ImageCardView;
|
|
import androidx.leanback.widget.ListRow;
|
|
import androidx.leanback.widget.ListRowPresenter;
|
|
import androidx.leanback.widget.ObjectAdapter;
|
|
import androidx.leanback.widget.OnItemViewClickedListener;
|
|
import androidx.leanback.widget.Presenter;
|
|
import androidx.leanback.widget.Row;
|
|
import androidx.leanback.widget.RowPresenter;
|
|
import androidx.leanback.widget.SpeechRecognitionCallback;
|
|
import androidx.core.app.ActivityOptionsCompat;
|
|
import androidx.loader.app.LoaderManager;
|
|
import androidx.loader.content.CursorLoader;
|
|
import androidx.loader.content.Loader;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.widget.Toast;
|
|
|
|
import com.liskovsoft.smartyoutubetv2.tv.BuildConfig;
|
|
import com.liskovsoft.smartyoutubetv2.tv.R;
|
|
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
|
|
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
|
|
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
|
|
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
|
|
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity;
|
|
|
|
/*
|
|
* This class demonstrates how to do in-app search
|
|
*/
|
|
public class SearchFragment extends SearchSupportFragment
|
|
implements SearchSupportFragment.SearchResultProvider,
|
|
LoaderManager.LoaderCallbacks<Cursor> {
|
|
private static final String TAG = "SearchFragment";
|
|
private static final boolean DEBUG = BuildConfig.DEBUG;
|
|
private static final boolean FINISH_ON_RECOGNIZER_CANCELED = true;
|
|
private static final int REQUEST_SPEECH = 0x00000010;
|
|
|
|
private final Handler mHandler = new Handler();
|
|
private ArrayObjectAdapter mRowsAdapter;
|
|
private String mQuery;
|
|
private final CursorObjectAdapter mVideoCursorAdapter =
|
|
new CursorObjectAdapter(new CardPresenter());
|
|
|
|
private int mSearchLoaderId = 1;
|
|
private boolean mResultsFound = false;
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
|
mVideoCursorAdapter.setMapper(new VideoCursorMapper());
|
|
|
|
setSearchResultProvider(this);
|
|
setOnItemViewClickedListener(new ItemViewClickedListener());
|
|
if (DEBUG) {
|
|
Log.d(TAG, "User is initiating a search. Do we have RECORD_AUDIO permission? " +
|
|
hasPermission(Manifest.permission.RECORD_AUDIO));
|
|
}
|
|
if (!hasPermission(Manifest.permission.RECORD_AUDIO)) {
|
|
if (DEBUG) {
|
|
Log.d(TAG, "Does not have RECORD_AUDIO, using SpeechRecognitionCallback");
|
|
}
|
|
// 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
|
|
setSpeechRecognitionCallback(new SpeechRecognitionCallback() {
|
|
@Override
|
|
public void recognizeSpeech() {
|
|
try {
|
|
startActivityForResult(getRecognizerIntent(), REQUEST_SPEECH);
|
|
} catch (ActivityNotFoundException e) {
|
|
Log.e(TAG, "Cannot find activity for speech recognizer", e);
|
|
}
|
|
}
|
|
});
|
|
} else if (DEBUG) {
|
|
Log.d(TAG, "We DO have RECORD_AUDIO");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
mHandler.removeCallbacksAndMessages(null);
|
|
super.onPause();
|
|
}
|
|
|
|
@Override
|
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
switch (requestCode) {
|
|
case REQUEST_SPEECH:
|
|
switch (resultCode) {
|
|
case Activity.RESULT_OK:
|
|
setSearchQuery(data, true);
|
|
break;
|
|
default:
|
|
// If recognizer is canceled or failed, keep focus on the search orb
|
|
if (FINISH_ON_RECOGNIZER_CANCELED) {
|
|
if (!hasResults()) {
|
|
if (DEBUG) Log.v(TAG, "Voice search canceled");
|
|
getView().findViewById(R.id.lb_search_bar_speech_orb).requestFocus();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ObjectAdapter getResultsAdapter() {
|
|
return mRowsAdapter;
|
|
}
|
|
|
|
@Override
|
|
public boolean onQueryTextChange(String newQuery) {
|
|
if (DEBUG) Log.i(TAG, String.format("Search text changed: %s", newQuery));
|
|
loadQuery(newQuery);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onQueryTextSubmit(String query) {
|
|
if (DEBUG) Log.i(TAG, String.format("Search text submitted: %s", query));
|
|
loadQuery(query);
|
|
return true;
|
|
}
|
|
|
|
public boolean hasResults() {
|
|
return mRowsAdapter.size() > 0 && mResultsFound;
|
|
}
|
|
|
|
private boolean hasPermission(final String permission) {
|
|
final Context context = getActivity();
|
|
return PackageManager.PERMISSION_GRANTED == context.getPackageManager().checkPermission(
|
|
permission, context.getPackageName());
|
|
}
|
|
|
|
private void loadQuery(String query) {
|
|
if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
|
|
mQuery = query;
|
|
getLoaderManager().initLoader(mSearchLoaderId++, null, this);
|
|
}
|
|
}
|
|
|
|
public void focusOnSearch() {
|
|
getView().findViewById(R.id.lb_search_bar).requestFocus();
|
|
}
|
|
|
|
@Override
|
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
|
String query = mQuery;
|
|
return new CursorLoader(
|
|
getActivity(),
|
|
VideoContract.VideoEntry.CONTENT_URI,
|
|
null, // Return all fields.
|
|
VideoContract.VideoEntry.COLUMN_NAME + " LIKE ? OR " +
|
|
VideoContract.VideoEntry.COLUMN_DESC + " LIKE ?",
|
|
new String[]{"%" + query + "%", "%" + query + "%"},
|
|
null // Default sort order
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
|
|
int titleRes;
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
mResultsFound = true;
|
|
titleRes = R.string.search_results;
|
|
} else {
|
|
mResultsFound = false;
|
|
titleRes = R.string.no_search_results;
|
|
}
|
|
mVideoCursorAdapter.changeCursor(cursor);
|
|
HeaderItem header = new HeaderItem(getString(titleRes, mQuery));
|
|
mRowsAdapter.clear();
|
|
ListRow row = new ListRow(header, mVideoCursorAdapter);
|
|
mRowsAdapter.add(row);
|
|
}
|
|
|
|
@Override
|
|
public void onLoaderReset(Loader<Cursor> loader) {
|
|
mVideoCursorAdapter.changeCursor(null);
|
|
}
|
|
|
|
private final class ItemViewClickedListener implements OnItemViewClickedListener {
|
|
@Override
|
|
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
|
|
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
|
|
|
if (item instanceof Video) {
|
|
Video video = (Video) item;
|
|
Intent intent = new Intent(getActivity(), VideoDetailsActivity.class);
|
|
intent.putExtra(VideoDetailsActivity.VIDEO, video);
|
|
|
|
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
|
getActivity(),
|
|
((ImageCardView) itemViewHolder.view).getMainImageView(),
|
|
VideoDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
|
|
getActivity().startActivity(intent, bundle);
|
|
} else {
|
|
Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|