Update Search UI

pull/102/head
FongMi 4 years ago
parent 68b0bd432b
commit acc4c50623
  1. 71
      app/src/leanback/java/com/fongmi/android/tv/ui/activity/SearchActivity.java
  2. 2
      app/src/leanback/java/com/fongmi/android/tv/ui/adapter/KeyboardAdapter.java
  3. 10
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyDown.java
  4. 10
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomKeyboard.java
  5. 71
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomMic.java
  6. 6
      app/src/leanback/java/com/fongmi/android/tv/ui/custom/CustomTitleView.java
  7. 10
      app/src/leanback/res/drawable/ic_keyboard_space.xml
  8. 4
      app/src/leanback/res/drawable/ic_mic.xml
  9. 5
      app/src/leanback/res/drawable/selector_mic.xml
  10. 11
      app/src/leanback/res/drawable/shape_mic_focused.xml
  11. 7
      app/src/leanback/res/drawable/shape_mic_normal.xml
  12. 96
      app/src/leanback/res/layout/activity_search.xml
  13. 6
      app/src/leanback/res/values-zh-rCN/strings.xml
  14. 6
      app/src/leanback/res/values-zh-rTW/strings.xml
  15. 4
      app/src/main/java/com/fongmi/android/tv/utils/Utils.java

@ -6,15 +6,11 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.text.Editable;
import android.text.TextUtils;
import android.view.View;
import android.view.animation.Animation;
import android.view.inputmethod.EditorInfo;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@ -31,7 +27,6 @@ import com.fongmi.android.tv.ui.adapter.WordAdapter;
import com.fongmi.android.tv.ui.custom.CustomKeyboard;
import com.fongmi.android.tv.ui.custom.CustomListener;
import com.fongmi.android.tv.ui.custom.SpaceItemDecoration;
import com.fongmi.android.tv.utils.ResUtil;
import com.fongmi.android.tv.utils.Utils;
import java.io.IOException;
@ -42,13 +37,9 @@ import okhttp3.Response;
public class SearchActivity extends BaseActivity implements WordAdapter.OnClickListener, HistoryAdapter.OnClickListener, CustomKeyboard.Callback {
private final ActivityResultLauncher<String> launcher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> startListening());
private ActivitySearchBinding mBinding;
private SpeechRecognizer mRecognizer;
private HistoryAdapter mHistoryAdapter;
private WordAdapter mWordAdapter;
private Animation mFlicker;
private Handler mHandler;
public static void start(Activity activity) {
@ -62,9 +53,7 @@ public class SearchActivity extends BaseActivity implements WordAdapter.OnClickL
@Override
protected void initView() {
mFlicker = ResUtil.getAnim(R.anim.flicker);
mHandler = new Handler(Looper.getMainLooper());
mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
CustomKeyboard.init(this, mBinding);
setRecyclerView();
getHot();
@ -72,6 +61,7 @@ public class SearchActivity extends BaseActivity implements WordAdapter.OnClickL
@Override
protected void initEvent() {
mBinding.mic.setOnClickListener(view -> onMic());
mBinding.keyword.setOnEditorActionListener((textView, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) onSearch();
return true;
@ -83,10 +73,10 @@ public class SearchActivity extends BaseActivity implements WordAdapter.OnClickL
else getSuggest(s.toString());
}
});
mRecognizer.setRecognitionListener(new CustomListener() {
mBinding.mic.setListener(new CustomListener() {
@Override
public void onResults(String result) {
stopListening();
mBinding.mic.stop();
mBinding.keyword.setText(result);
mBinding.keyword.setSelection(mBinding.keyword.length());
}
@ -124,6 +114,14 @@ public class SearchActivity extends BaseActivity implements WordAdapter.OnClickL
});
}
public void onMic() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> mBinding.mic.start()).launch(Manifest.permission.RECORD_AUDIO);
} else {
mBinding.mic.start();
}
}
@Override
public void onItemClick(String text) {
mBinding.keyword.setText(text);
@ -150,56 +148,9 @@ public class SearchActivity extends BaseActivity implements WordAdapter.OnClickL
PushActivity.start(this);
}
@Override
public void onVoice() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
launcher.launch(Manifest.permission.RECORD_AUDIO);
} else {
startListening();
}
}
private void startListening() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mBinding.keyboard.setVisibility(View.INVISIBLE);
mBinding.voice.setVisibility(View.VISIBLE);
mBinding.voice.startAnimation(mFlicker);
mRecognizer.startListening(intent);
}
private void stopListening() {
mBinding.keyboard.setVisibility(View.VISIBLE);
mBinding.voice.setVisibility(View.GONE);
mBinding.voice.clearAnimation();
mRecognizer.stopListening();
}
private void destroyRecognizer() {
try {
mRecognizer.destroy();
} catch (Exception ignored) {
}
}
@Override
protected void onResume() {
super.onResume();
mBinding.keyword.requestFocus();
}
@Override
public void onBackPressed() {
if (mBinding.voice.getVisibility() == View.VISIBLE) {
stopListening();
} else {
super.onBackPressed();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
destroyRecognizer();
}
}

@ -20,7 +20,7 @@ public class KeyboardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private final List<Object> mItems;
public KeyboardAdapter(OnClickListener listener) {
this.mItems = Arrays.asList(R.drawable.ic_keyboard_remote, R.drawable.ic_keyboard_voice, R.drawable.ic_keyboard_left, R.drawable.ic_keyboard_right, R.drawable.ic_keyboard_back, R.drawable.ic_keyboard_search, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
this.mItems = Arrays.asList(R.drawable.ic_keyboard_remote, R.drawable.ic_keyboard_left, R.drawable.ic_keyboard_space, R.drawable.ic_keyboard_right, R.drawable.ic_keyboard_back, R.drawable.ic_keyboard_search, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
this.mListener = listener;
}

@ -7,7 +7,7 @@ import com.fongmi.android.tv.utils.Utils;
public class CustomKeyDown {
private final Listener mListener;
private int mHoldTime;
private int holdTime;
public static CustomKeyDown create(Listener listener) {
return new CustomKeyDown(listener);
@ -21,7 +21,7 @@ public class CustomKeyDown {
if (event.getAction() == KeyEvent.ACTION_DOWN && (Utils.isLeftKey(event) || Utils.isRightKey(event))) {
mListener.onSeeking(Utils.isRightKey(event) ? addTime() : subTime());
} else if (event.getAction() == KeyEvent.ACTION_UP && (Utils.isLeftKey(event) || Utils.isRightKey(event))) {
mListener.onSeekTo(mHoldTime);
mListener.onSeekTo(holdTime);
} else if (event.getAction() == KeyEvent.ACTION_UP && Utils.isDownKey(event)) {
mListener.onKeyDown();
} else if (event.getAction() == KeyEvent.ACTION_UP && Utils.isEnterKey(event)) {
@ -31,15 +31,15 @@ public class CustomKeyDown {
}
private int addTime() {
return mHoldTime = mHoldTime + 10000;
return holdTime = holdTime + 10000;
}
private int subTime() {
return mHoldTime = mHoldTime - 10000;
return holdTime = holdTime - 10000;
}
public void resetTime() {
mHoldTime = 0;
holdTime = 0;
}
public boolean hasEvent(KeyEvent event) {

@ -42,6 +42,11 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener {
StringBuilder sb = new StringBuilder(binding.keyword.getText().toString());
int cursor = binding.keyword.getSelectionStart();
switch (resId) {
case R.drawable.ic_keyboard_space:
sb.insert(cursor, " ");
binding.keyword.setText(sb.toString());
binding.keyword.setSelection(cursor + 1);
break;
case R.drawable.ic_keyboard_left:
binding.keyword.setSelection(--cursor < 0 ? 0 : cursor);
break;
@ -54,9 +59,6 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener {
binding.keyword.setText(sb.toString());
binding.keyword.setSelection(cursor - 1);
break;
case R.drawable.ic_keyboard_voice:
callback.onVoice();
break;
case R.drawable.ic_keyboard_remote:
callback.onRemote();
break;
@ -75,8 +77,6 @@ public class CustomKeyboard implements KeyboardAdapter.OnClickListener {
public interface Callback {
void onVoice();
void onRemote();
void onSearch();

@ -0,0 +1,71 @@
package com.fongmi.android.tv.ui.custom;
import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.animation.Animation;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import com.fongmi.android.tv.R;
import com.fongmi.android.tv.utils.ResUtil;
import com.fongmi.android.tv.utils.Utils;
import com.github.bassaer.library.MDColor;
public class CustomMic extends AppCompatImageView {
private SpeechRecognizer recognizer;
private Animation flicker;
public CustomMic(@NonNull Context context) {
super(context);
}
public CustomMic(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
flicker = ResUtil.getAnim(R.anim.flicker);
recognizer = SpeechRecognizer.createSpeechRecognizer(context);
}
public void setListener(CustomListener listener) {
recognizer.setRecognitionListener(listener);
}
public void start() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
setColorFilter(MDColor.RED_500, PorterDuff.Mode.SRC_IN);
recognizer.startListening(intent);
}
public boolean stop() {
setColorFilter(MDColor.WHITE, PorterDuff.Mode.SRC_IN);
recognizer.stopListening();
clearAnimation();
return true;
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, @Nullable Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
if (gainFocus) startAnimation(flicker);
else stop();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (Utils.isBackKey(event) && event.getAction() == KeyEvent.ACTION_UP) return stop();
else return super.dispatchKeyEvent(event);
}
}

@ -22,7 +22,7 @@ import java.util.List;
public class CustomTitleView extends AppCompatTextView {
private Listener mListener;
private Animation mFlicker;
private Animation flicker;
public CustomTitleView(@NonNull Context context) {
super(context);
@ -30,7 +30,7 @@ public class CustomTitleView extends AppCompatTextView {
public CustomTitleView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mFlicker = ResUtil.getAnim(R.anim.flicker);
flicker = ResUtil.getAnim(R.anim.flicker);
}
public void setListener(Listener listener) {
@ -40,7 +40,7 @@ public class CustomTitleView extends AppCompatTextView {
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused) startAnimation(mFlicker);
if (focused) startAnimation(flicker);
else clearAnimation();
}

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/white"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="@color/white"
android:pathData="M8,30V18H11V27H37V18H40V30Z" />
</vector>

@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:width="36dp"
android:height="36dp"
android:tint="@color/white"
android:viewportWidth="48"
android:viewportHeight="48">

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/shape_mic_focused" android:state_focused="true" />
<item android:drawable="@drawable/shape_mic_normal" />
</selector>

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black_30" />
<stroke
android:width="1dp"
android:color="@color/white" />
</shape>

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black_20" />
</shape>

@ -11,58 +11,11 @@
android:paddingTop="24dp"
android:paddingEnd="24dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="24dp"
android:orientation="vertical">
<com.fongmi.android.tv.ui.custom.CustomEditText
android:id="@+id/keyword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="@null"
android:hint="@string/search_keyword"
android:imeOptions="actionDone"
android:inputType="textCapCharacters|textAutoCorrect|textAutoComplete"
android:letterSpacing="0.02"
android:maxLength="20"
android:singleLine="true"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@drawable/shape_cursor"
android:textSize="24sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="6"
tools:itemCount="36"
tools:listitem="@layout/adapter_keyboard_text" />
<ImageView
android:id="@+id/voice"
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@drawable/ic_keyboard_voice"
android:visibility="gone"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/historyLayout"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_marginEnd="24dp"
android:layout_marginEnd="36dp"
android:orientation="vertical">
<TextView
@ -86,9 +39,56 @@
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="36dp"
android:orientation="vertical">
<com.fongmi.android.tv.ui.custom.CustomMic
android:id="@+id/mic"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="12dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_mic" />
<com.fongmi.android.tv.ui.custom.CustomEditText
android:id="@+id/keyword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_toEndOf="@+id/mic"
android:background="@null"
android:hint="@string/search_keyword"
android:imeOptions="actionDone"
android:inputType="textCapCharacters|textAutoCorrect|textAutoComplete"
android:letterSpacing="0.02"
android:maxLength="20"
android:singleLine="true"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textCursorDrawable="@drawable/shape_cursor"
android:textSize="24sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/keyboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/keyword"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="6"
tools:itemCount="36"
tools:listitem="@layout/adapter_keyboard_text" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="24dp"
android:orientation="vertical">
<TextView

@ -11,9 +11,9 @@
<!-- Search -->
<string name="search_keyword">关键字…</string>
<string name="search_history">历史纪录</string>
<string name="search_suggest">建议搜索</string>
<string name="search_hot"></string>
<string name="search_history">历史</string>
<string name="search_suggest">建议</string>
<string name="search_hot">热搜</string>
<!-- Collect -->
<string name="collect_result"><xliff:g name="name">%s</xliff:g>”的搜索结果</string>

@ -11,9 +11,9 @@
<!-- Search -->
<string name="search_keyword">關鍵字…</string>
<string name="search_history">歷史紀錄</string>
<string name="search_suggest">建議搜尋</string>
<string name="search_hot"></string>
<string name="search_history">歷史</string>
<string name="search_suggest">建議</string>
<string name="search_hot">熱搜</string>
<!-- Collect -->
<string name="collect_result"><xliff:g name="name">%s</xliff:g>」的搜尋結果</string>

@ -36,6 +36,10 @@ public class Utils {
return event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT;
}
public static boolean isBackKey(KeyEvent event) {
return event.getKeyCode() == KeyEvent.KEYCODE_BACK;
}
public static void hideSystemUI(Activity activity) {
int flags = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);

Loading…
Cancel
Save