com.android.talkback.tutorial.TutorialLessonFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.android.talkback.tutorial.TutorialLessonFragment.java

Source

/*
 * Copyright (C) 2015 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.android.talkback.tutorial;

import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toolbar;
import com.android.talkback.R;
import com.android.talkback.SpeechController;
import com.android.talkback.contextmenu.MenuActionInterceptor;
import com.android.talkback.contextmenu.MenuManager;
import com.android.talkback.contextmenu.MenuTransformer;
import com.android.talkback.controller.GestureActionMonitor;
import com.android.talkback.tutorial.exercise.Exercise;
import com.google.android.marvin.talkback.TalkBackService;

public class TutorialLessonFragment extends Fragment
        implements View.OnClickListener, Exercise.ExerciseCallback, GestureActionMonitor.GestureActionListener {

    private static final int DELAY_BEFORE_ANNOUNCE_LESSON = 100;
    private static final int DELAY_BEFORE_AUTO_MOVE_TO_NEXT_LESSON = 1000;

    private TutorialController mTutorialController;
    private TutorialLesson mLesson;
    private TutorialLessonPage mPage;
    private Exercise mExercise;
    private int mCurrentPage;
    private TutorialNavigationCallback mCallback;
    private TextView mDescription;
    private SpeechController mSpeechController;
    private GestureActionMonitor mActionMonitor = new GestureActionMonitor();
    private Handler mHandler = new Handler(Looper.getMainLooper());

    public void setLesson(TutorialLesson lesson, int currentPage) {
        mLesson = lesson;
        mPage = mLesson.getLessonPage(currentPage);
        mCurrentPage = currentPage;
        mExercise = mPage.getExercise();
    }

    public void setTutorialController(TutorialController tutorialController) {
        mTutorialController = tutorialController;
    }

    public void setTutorialNavigationCallback(TutorialNavigationCallback callback) {
        mCallback = callback;
    }

    @Override
    public void onCreate(Bundle instance) {
        super.onCreate(instance);
        setRetainInstance(true);
        setHasOptionsMenu(true);
        mExercise.setExerciseCallBack(this);

        TalkBackService service = TalkBackService.getInstance();
        if (service != null) {
            mSpeechController = service.getSpeechController();
        }

        mActionMonitor.setListener(this);
    }

    @Override
    public void onStart() {
        super.onStart();

        MenuTransformer menuTransformer = mExercise.getContextMenuTransformer();
        MenuActionInterceptor menuActionInterceptor = mExercise.getContextMenuActionInterceptor();
        TalkBackService service = TalkBackService.getInstance();
        if (service != null) {
            MenuManager menuManager = service.getMenuManager();
            menuManager.setMenuTransformer(menuTransformer);
            menuManager.setMenuActionInterceptor(menuActionInterceptor);
        }

        // We need to post the announcements delayed in order to ensure that the view changed
        // event gets sent beforehand. This makes the TalkBack speech response flow more logical.
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                View view = getView();
                if (view == null) {
                    // Something terrible has happened, e.g. the fragment is gone.
                    return;
                }

                view.announceForAccessibility(getTitle());
                view.announceForAccessibility(mPage.getSubtitle());
                mDescription.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
            }
        }, DELAY_BEFORE_ANNOUNCE_LESSON);
        mExercise.onInitialized(getActivity());
    }

    @Override
    public void onStop() {
        super.onStop();
        mExercise.clear();
        TalkBackService service = TalkBackService.getInstance();
        if (service != null) {
            service.getMenuManager().setMenuTransformer(null);
            service.getMenuManager().setMenuActionInterceptor(null);
            service.getSpeechController().interrupt();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        Activity activity = getActivity();
        if (activity != null) {
            ActionBar actionBar = activity.getActionBar();
            actionBar.setDisplayHomeAsUpEnabled(false);
            actionBar.setDisplayShowHomeEnabled(false);
            actionBar.setDisplayShowCustomEnabled(true);
            actionBar.setDisplayShowTitleEnabled(false);
            actionBar.setCustomView(R.layout.tutorial_action_bar);
            actionBar.getCustomView().findViewById(R.id.up).setOnClickListener(this);
            TextView title = (TextView) actionBar.getCustomView().findViewById(R.id.action_bar_title);
            title.setText(getTitle());
            LocalBroadcastManager.getInstance(activity).registerReceiver(mActionMonitor,
                    GestureActionMonitor.FILTER);
        }

        TalkBackService service = TalkBackService.getInstance();
        if (service != null) {
            service.addEventListener(mExercise);
        }
    }

    private String getTitle() {
        if (!TextUtils.isEmpty(mPage.getTitle())) {
            return mPage.getTitle();
        } else {
            return mLesson.getTitle();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        TalkBackService service = TalkBackService.getInstance();
        if (service != null) {
            service.postRemoveEventListener(mExercise);
        }

        Activity activity = getActivity();
        if (activity != null) {
            LocalBroadcastManager.getInstance(activity).unregisterReceiver(mActionMonitor);
        }

        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
        int layoutId;
        if (mExercise.needScrollableContainer()) {
            layoutId = R.layout.tutorial_lesson_fragment_scrollable;
        } else {
            layoutId = R.layout.tutorial_lesson_fragment;
        }
        View view = inflater.inflate(layoutId, container, false);

        mDescription = (TextView) view.findViewById(R.id.description);
        mDescription.setText(mPage.getDescription());

        TextView subTitle = (TextView) view.findViewById(R.id.part_subtitle);
        subTitle.setText(mPage.getSubtitle());

        TextView currentPage = (TextView) view.findViewById(R.id.current_page);
        TextView next = (TextView) view.findViewById(R.id.next);
        if (mCurrentPage < mLesson.getPagesCount() - 1) {
            next.setText(R.string.tutorial_next);
            currentPage.setVisibility(View.VISIBLE);
            currentPage.setText(
                    getString(R.string.tutorial_page_number_of, mCurrentPage + 1, mLesson.getPagesCount() - 1));
        } else if (mTutorialController.getNextLesson(mLesson) == null) {
            next.setText(R.string.tutorial_home);
        } else {
            next.setText(R.string.tutorial_next_lesson);
        }
        next.setOnClickListener(this);

        View previous = view.findViewById(R.id.previous_page);
        previous.setOnClickListener(this);
        previous.setContentDescription(getString(R.string.tutorial_previous));

        ViewGroup contentContainer = (ViewGroup) view.findViewById(R.id.practice_area);
        View contentView = mPage.getExercise().getContentView(inflater, contentContainer);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        contentContainer.addView(contentView, params);

        return view;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.next:
            if (mCallback != null) {
                mCallback.onNextPageClicked(mLesson, mCurrentPage);
            }
            break;
        case R.id.previous_page:
            if (mCallback != null) {
                mCallback.onPreviousPageClicked(mLesson, mCurrentPage);
            }
            break;
        case R.id.up:
            mCallback.onNavigateUpClicked();
            break;
        }
    }

    @Override
    public void onExerciseCompleted(boolean autoSwitchLesson, int completeMessageResId) {
        if (mSpeechController == null) {
            return;
        }

        SpeechController.UtteranceCompleteRunnable speechCallback = null;

        if (autoSwitchLesson) {
            speechCallback = new SpeechController.UtteranceCompleteRunnable() {
                @Override
                public void run(int status) {
                    moveToNextPageWithDelay(DELAY_BEFORE_AUTO_MOVE_TO_NEXT_LESSON);
                }
            };
        }
        notifyExerciseCompleted(speechCallback, completeMessageResId);
    }

    private void notifyExerciseCompleted(final SpeechController.UtteranceCompleteRunnable callback,
            final int completeMessageResId) {
        if (!isResumed()) {
            return;
        }

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mSpeechController.speak(getString(completeMessageResId), null, null,
                        SpeechController.QUEUE_MODE_UNINTERRUPTIBLE, 0, 0, null, null, callback);
            }
        }, DELAY_BEFORE_AUTO_MOVE_TO_NEXT_LESSON);
    }

    private void moveToNextPageWithDelay(long delay) {
        if (!isResumed()) {
            return;
        }

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (getActivity() != null) {
                    mCallback.onNextPageClicked(mLesson, mCurrentPage);
                }
            }
        }, delay);
    }

    @Override
    public void onGestureAction(String action) {
        if (mExercise == null || TextUtils.isEmpty(action) || getActivity() == null) {
            return;
        }

        mExercise.onAction(getActivity(), action);
    }
}