1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.example.sampleleanbacklauncher.search;
18 
19 import android.app.Fragment;
20 import android.content.ActivityNotFoundException;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.graphics.Outline;
24 import android.graphics.Rect;
25 import android.os.Bundle;
26 import android.os.Trace;
27 import androidx.annotation.Nullable;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.view.ViewOutlineProvider;
33 import android.widget.Toast;
34 
35 import com.example.sampleleanbacklauncher.R;
36 
37 public class SearchFragment extends Fragment
38         implements View.OnClickListener, View.OnFocusChangeListener {
39     private static final String TAG = "SearchFragment";
40 
41     private static final String EXTRA_SEARCH_TYPE = "search_type";
42 
43     private static final int SEARCH_TYPE_VOICE = 1;
44     private static final int SEARCH_TYPE_KEYBOARD = 2;
45 
46     private View mSearchOrbVoice;
47     private View mSearchOrbKeyboard;
48 
newInstance()49     public static SearchFragment newInstance() {
50         Bundle args = new Bundle();
51 
52         SearchFragment fragment = new SearchFragment();
53         fragment.setArguments(args);
54         return fragment;
55     }
56 
57     @Nullable
58     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)59     public View onCreateView(LayoutInflater inflater, ViewGroup container,
60             Bundle savedInstanceState) {
61         final View root = inflater.inflate(R.layout.search, container, false);
62 
63         final ViewOutlineProvider outlineProvider = new ViewOutlineProvider() {
64             @Override
65             public void getOutline(View view, Outline outline) {
66                 outline.setOval(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
67             }
68         };
69 
70         mSearchOrbVoice = root.findViewById(R.id.search_orb_voice);
71         mSearchOrbVoice.setOnFocusChangeListener(this);
72         mSearchOrbVoice.setOutlineProvider(outlineProvider);
73         mSearchOrbVoice.setClipToOutline(true);
74         mSearchOrbVoice.setOnClickListener(this);
75 
76         mSearchOrbKeyboard = root.findViewById(R.id.search_orb_keyboard);
77         mSearchOrbKeyboard.setOnFocusChangeListener(this);
78         mSearchOrbKeyboard.setOutlineProvider(outlineProvider);
79         mSearchOrbKeyboard.setClipToOutline(true);
80         mSearchOrbKeyboard.setOnClickListener(this);
81 
82         return root;
83     }
84 
85     @Override
onDestroyView()86     public void onDestroyView() {
87         super.onDestroyView();
88         mSearchOrbVoice.setOnFocusChangeListener(null);
89         mSearchOrbKeyboard.setOnFocusChangeListener(null);
90     }
91 
92     @Override
onClick(View v)93     public void onClick(View v) {
94         final Intent intent = new Intent(Intent.ACTION_ASSIST)
95                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
96                         | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
97         intent.putExtra(EXTRA_SEARCH_TYPE,
98                 v == mSearchOrbKeyboard ? SEARCH_TYPE_KEYBOARD : SEARCH_TYPE_VOICE);
99         try {
100             startActivity(intent);
101             mSearchOrbVoice.requestFocus();
102         } catch (ActivityNotFoundException e) {
103             Log.e(TAG, "Exception launching intent " + intent, e);
104             Toast.makeText(getContext(), getString(R.string.app_unavailable),
105                     Toast.LENGTH_SHORT).show();
106         }
107     }
108 
109     @Override
onFocusChange(View v, boolean hasFocus)110     public void onFocusChange(View v, boolean hasFocus) {
111         Trace.beginSection("SearchFragment.onFocusChange");
112         try {
113             final View root = getView();
114             if (root == null) {
115                 return;
116             }
117             root.requestRectangleOnScreen(
118                     new Rect(0, 0, root.getMeasuredWidth(), root.getMeasuredHeight()));
119 
120             final int visibility = hasFocus ? View.VISIBLE : View.GONE;
121             if (v == mSearchOrbKeyboard) {
122                 root.findViewById(R.id.search_text_keyboard).setVisibility(visibility);
123             } else {
124                 root.findViewById(R.id.search_text_voice).setVisibility(visibility);
125             }
126 
127             final Resources resources = getResources();
128             float elevation = resources.getDimension(hasFocus
129                     ? R.dimen.search_item_focused_z : R.dimen.search_item_unfocused_z);
130             float scale = hasFocus
131                     ? resources.getFraction(R.fraction.search_item_focused_zoom, 1, 1) : 1.0f;
132             int duration = resources.getInteger(R.integer.search_orb_scale_duration_ms);
133 
134             v.animate().z(elevation).scaleX(scale).scaleY(scale).setDuration(duration);
135         } finally {
136             Trace.endSection();
137         }
138     }
139 }
140