Home | History | Annotate | Download | only in setup
      1 /*
      2  * Copyright (C) 2015 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.android.tv.common.ui.setup;
     18 
     19 import static android.content.Context.ACCESSIBILITY_SERVICE;
     20 
     21 import android.os.Bundle;
     22 import android.support.v17.leanback.app.GuidedStepFragment;
     23 import android.support.v17.leanback.widget.GuidanceStylist;
     24 import android.support.v17.leanback.widget.GuidedAction;
     25 import android.support.v17.leanback.widget.GuidedActionsStylist;
     26 import android.support.v17.leanback.widget.VerticalGridView;
     27 import android.view.LayoutInflater;
     28 import android.view.View;
     29 import android.view.View.AccessibilityDelegate;
     30 import android.view.ViewGroup;
     31 import android.view.ViewGroup.MarginLayoutParams;
     32 import android.view.accessibility.AccessibilityEvent;
     33 import android.view.accessibility.AccessibilityManager;
     34 import android.view.accessibility.AccessibilityNodeInfo;
     35 import android.widget.LinearLayout;
     36 import com.android.tv.common.R;
     37 
     38 /** A fragment for channel source info/setup. */
     39 public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
     40     /**
     41      * Key of the argument which indicate whether the parent of this fragment has three panes.
     42      *
     43      * <p>Value type: boolean
     44      */
     45     public static final String KEY_THREE_PANE = "key_three_pane";
     46 
     47     private View mContentFragment;
     48     private boolean mFromContentFragment;
     49     private boolean mAccessibilityMode;
     50 
     51     @Override
     52     public View onCreateView(
     53             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     54         View view = super.onCreateView(inflater, container, savedInstanceState);
     55         Bundle arguments = getArguments();
     56         view.findViewById(android.support.v17.leanback.R.id.action_fragment_root)
     57                 .setPadding(0, 0, 0, 0);
     58         mContentFragment = view.findViewById(android.support.v17.leanback.R.id.content_fragment);
     59         LinearLayout.LayoutParams guidanceLayoutParams =
     60                 (LinearLayout.LayoutParams) mContentFragment.getLayoutParams();
     61         guidanceLayoutParams.weight = 0;
     62         if (arguments != null && arguments.getBoolean(KEY_THREE_PANE, false)) {
     63             // Content fragment.
     64             guidanceLayoutParams.width =
     65                     getResources()
     66                             .getDimensionPixelOffset(
     67                                     R.dimen.setup_guidedstep_guidance_section_width_3pane);
     68             int doneButtonWidth =
     69                     getResources()
     70                             .getDimensionPixelOffset(R.dimen.setup_done_button_container_width);
     71             // Guided actions list
     72             View list = view.findViewById(android.support.v17.leanback.R.id.guidedactions_list);
     73             MarginLayoutParams marginLayoutParams = (MarginLayoutParams) list.getLayoutParams();
     74             // Use content view to check layout direction while view is being created.
     75             if (getResources().getConfiguration().getLayoutDirection()
     76                     == View.LAYOUT_DIRECTION_LTR) {
     77                 marginLayoutParams.rightMargin = doneButtonWidth;
     78             } else {
     79                 marginLayoutParams.leftMargin = doneButtonWidth;
     80             }
     81         } else {
     82             // Content fragment.
     83             guidanceLayoutParams.width =
     84                     getResources()
     85                             .getDimensionPixelOffset(
     86                                     R.dimen.setup_guidedstep_guidance_section_width_2pane);
     87         }
     88         // gridView Alignment
     89         VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView();
     90         int offset =
     91                 getResources()
     92                         .getDimensionPixelOffset(R.dimen.setup_guidedactions_selector_margin_top);
     93         gridView.setWindowAlignmentOffset(offset);
     94         gridView.setWindowAlignmentOffsetPercent(0);
     95         gridView.setItemAlignmentOffsetPercent(0);
     96         ((ViewGroup) view.findViewById(android.support.v17.leanback.R.id.guidedactions_list))
     97                 .setTransitionGroup(false);
     98         // Needed for the shared element transition.
     99         // content_frame is defined in leanback.
    100         ViewGroup group =
    101                 (ViewGroup) view.findViewById(android.support.v17.leanback.R.id.content_frame);
    102         group.setClipChildren(false);
    103         group.setClipToPadding(false);
    104         return view;
    105     }
    106 
    107     @Override
    108     public GuidedActionsStylist onCreateActionsStylist() {
    109         return new SetupGuidedStepFragmentGuidedActionsStylist();
    110     }
    111 
    112     @Override
    113     public void onResume() {
    114         super.onResume();
    115         AccessibilityManager am =
    116                 (AccessibilityManager) getActivity().getSystemService(ACCESSIBILITY_SERVICE);
    117         mAccessibilityMode = am != null && am.isEnabled() && am.isTouchExplorationEnabled();
    118         mContentFragment.setFocusable(mAccessibilityMode);
    119         if (mAccessibilityMode) {
    120             mContentFragment.setAccessibilityDelegate(
    121                 new AccessibilityDelegate() {
    122                     @Override
    123                     public boolean performAccessibilityAction(View host, int action, Bundle args) {
    124                         if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS
    125                                 && !getActions().isEmpty()) {
    126                             // scroll to the top. This makes the first action view on the screen.
    127                             // Otherwise, the view can be recycled, so accessibility events cannot
    128                             // be sent later.
    129                             getGuidedActionsStylist().getActionsGridView().scrollToPosition(0);
    130                             mFromContentFragment = true;
    131                         }
    132                         return super.performAccessibilityAction(host, action, args);
    133                     }
    134                 });
    135             mContentFragment.requestFocus();
    136         }
    137     }
    138 
    139     @Override
    140     public GuidanceStylist onCreateGuidanceStylist() {
    141         return new GuidanceStylist() {
    142             @Override
    143             public View onCreateView(
    144                     LayoutInflater inflater, ViewGroup container, Guidance guidance) {
    145                 View view = super.onCreateView(inflater, container, guidance);
    146                 if (guidance.getIconDrawable() == null) {
    147                     // Icon view should not take up space when we don't use image.
    148                     getIconView().setVisibility(View.GONE);
    149                 }
    150                 return view;
    151             }
    152         };
    153     }
    154 
    155     protected abstract String getActionCategory();
    156 
    157     protected View getDoneButton() {
    158         return getActivity().findViewById(R.id.button_done);
    159     }
    160 
    161     @Override
    162     public void onGuidedActionClicked(GuidedAction action) {
    163         if (!action.isFocusable()) {
    164             // an unfocusable action may be clicked in accessibility mode when it's accessibility
    165             // focused
    166             return;
    167         }
    168         SetupActionHelper.onActionClick(this, getActionCategory(), (int) action.getId());
    169     }
    170 
    171     @Override
    172     protected void onProvideFragmentTransitions() {
    173         // Don't use the fragment transition defined in GuidedStepFragment.
    174     }
    175 
    176     @Override
    177     public boolean isFocusOutEndAllowed() {
    178         return true;
    179     }
    180 
    181     protected void setAccessibilityDelegate(GuidedActionsStylist.ViewHolder vh,
    182             GuidedAction action) {
    183         if (!mAccessibilityMode || findActionPositionById(action.getId()) == 0) {
    184             return;
    185         }
    186         vh.itemView.setAccessibilityDelegate(
    187                 new AccessibilityDelegate() {
    188                     @Override
    189                     public boolean performAccessibilityAction(View host, int action, Bundle args) {
    190                         if ((action == AccessibilityNodeInfo.ACTION_FOCUS
    191                                 || action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)
    192                                 && mFromContentFragment) {
    193                             // block the action and make the first action view accessibility focused
    194                             View view = getActionItemView(0);
    195                             if (view != null) {
    196                                 view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
    197                                 mFromContentFragment = false;
    198                                 return true;
    199                             }
    200                         }
    201                         return super.performAccessibilityAction(host, action, args);
    202                     }
    203                 });
    204     }
    205 
    206     private class SetupGuidedStepFragmentGuidedActionsStylist extends GuidedActionsStylist {
    207 
    208         @Override
    209         public void onBindViewHolder(GuidedActionsStylist.ViewHolder vh, GuidedAction action) {
    210             super.onBindViewHolder(vh, action);
    211             setAccessibilityDelegate(vh, action);
    212         }
    213     }
    214 }
    215