ru.yandex.subtitles.ui.activity.ConversationActivity.java Source code

Java tutorial

Introduction

Here is the source code for ru.yandex.subtitles.ui.activity.ConversationActivity.java

Source

/**
 * Copyright 2015 YA LLC
 * <p/>
 * 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
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * 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 ru.yandex.subtitles.ui.activity;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBar;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;

import ru.yandex.speechkit.Error;
import ru.yandex.subtitles.R;
import ru.yandex.subtitles.analytics.ConversationMetadata;
import ru.yandex.subtitles.content.Subscribeable;
import ru.yandex.subtitles.service.MessagingService;
import ru.yandex.subtitles.service.messaging.CreateConversationBroadcastReceiver;
import ru.yandex.subtitles.service.speechkit.ErrorResolver;
import ru.yandex.subtitles.service.speechkit.initializer.SpeechKitInitializedBroadcastReceiver;
import ru.yandex.subtitles.service.speechkit.recognition.RecognitionBroadcastReceiver;
import ru.yandex.subtitles.ui.fragment.conversations.ConversationFragment;
import ru.yandex.subtitles.ui.fragment.conversations.ZoomedMessagesFragment;
import ru.yandex.subtitles.ui.fragment.interactive.NoConnectionDialogFragment;
import ru.yandex.subtitles.ui.widget.InterceptableToolbar;
import ru.yandex.subtitles.ui.widget.microphonebar.MicrophoneBarController;
import ru.yandex.subtitles.ui.widget.microphonebar.MicrophoneBarListener;
import ru.yandex.subtitles.ui.widget.microphonebar.MicrophoneBarView;
import ru.yandex.subtitles.utils.ApplicationUtils;
import ru.yandex.subtitles.utils.IntentUtils;
import ru.yandex.subtitles.utils.NetworkBroadcastReceiver;
import ru.yandex.subtitles.utils.NetworkUtils;

public class ConversationActivity extends AbstractActivity
        implements CreateConversationBroadcastReceiver.OnCreateConversationListener,
        ConversationFragment.OnConversationListener, ZoomedMessagesFragment.OnZoomedMessagesListener,
        MicrophoneBarListener, SpeechKitInitializedBroadcastReceiver.OnSpeechKitInitializedListener,
        RecognitionBroadcastReceiver.RecognitionLifecycleCallbacks,
        NetworkBroadcastReceiver.OnNetworkStateChangeListener {

    private static final String KEY_HAS_CREATE_CONVERSATION_RECEIVER = "has_create_conversation_receiver";
    private static final String KEY_START_RECOGNITION = "start_recognition";
    private static final String KEY_THREAD = "thread_id";
    private static final String KEY_METADATA = "metadata";
    private static final String KEY_HAS_NETWORK_ERROR = "has_network_error";

    private static final String EXTRA_THREAD = "thread_id";
    private static final String EXTRA_FROM_WIDGET = "from_widget";

    public static void startConversation(final Context context) {
        startConversation(context, null);
    }

    @NonNull
    public static Intent createStartConversationIntent(final Context context, @Nullable final Integer appWidgetId,
            @Nullable final String phrase) {
        final Intent intent = IntentUtils.createActionIntent(context, ConversationActivity.class,
                Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_TEXT, phrase);
        intent.putExtra(EXTRA_FROM_WIDGET, appWidgetId != null);
        return intent;
    }

    public static void startConversation(final Context context, @Nullable final String phrase) {
        final Intent intent = createStartConversationIntent(context, null, phrase);
        context.startActivity(intent);
    }

    public static void openConversation(final Context context, final long threadId) {
        final Intent intent = IntentUtils.createActionIntent(context, ConversationActivity.class,
                Intent.ACTION_VIEW);
        intent.putExtra(EXTRA_THREAD, threadId);
        context.startActivity(intent);
    }

    private Subscribeable mSpeechKitReceiver;
    private Subscribeable mCreateConversationReceiver;
    private Subscribeable mRecognitionReceiver;

    private boolean mHasNetworkError = false;
    private Subscribeable mNetworkChangesReceiver;

    private MicrophoneBarView mMicrophoneBarView;

    private boolean mRecognitionStarted = false;
    private boolean mSpeechKitInitialized = false;
    private long mThreadId = -1;
    private ConversationMetadata mMetadata;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conversation);

        mMicrophoneBarView = findView(R.id.microphone_bar);
        mMicrophoneBarView.setMicrophoneBarListener(this);

        final InterceptableToolbar toolbar = findView(R.id.toolbar);
        if (ApplicationUtils.hasLollipop()) {
            toolbar.setElevation(0.f);
        }
        toolbar.setNavigationIcon(R.drawable.ic_ab_back_mtrl_black);
        toolbar.setIntersectionTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View v, final MotionEvent event) {
                return mMicrophoneBarView.onTouchEvent(event);
            }
        });
        setSupportActionBar(toolbar);

        final ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayShowTitleEnabled(false);
        }

        if (savedInstanceState == null) {
            mMetadata = new ConversationMetadata();
            parseIntent(getIntent());

        } else {
            mThreadId = savedInstanceState.getLong(KEY_THREAD);
            mMetadata = savedInstanceState.getParcelable(KEY_METADATA);
            mHasNetworkError = savedInstanceState.getBoolean(KEY_HAS_NETWORK_ERROR);
            mRecognitionStarted = savedInstanceState.getBoolean(KEY_START_RECOGNITION);

            if (savedInstanceState.getBoolean(KEY_HAS_CREATE_CONVERSATION_RECEIVER)) {
                registerCreateConversationReceiver();

            } else {
                registerRecognitionReceiver();
            }
        }

        mSpeechKitReceiver = new SpeechKitInitializedBroadcastReceiver(this);
        mSpeechKitReceiver.subscribe(this);
        MessagingService.initializeSpeechKit(this);

        mNetworkChangesReceiver = new NetworkBroadcastReceiver(this, true);
    }

    private void parseIntent(final Intent intent) {
        final String action = intent.getAction();
        if (Intent.ACTION_SEND.equals(action)) {
            final boolean fromWidget = intent.getBooleanExtra(EXTRA_FROM_WIDGET, false);
            mMetadata.setFromWidget(fromWidget);

            final String phrase = intent.getStringExtra(Intent.EXTRA_TEXT);
            createConversationWithPhrase(phrase);

        } else if (Intent.ACTION_VIEW.equals(action)) {
            mThreadId = intent.getLongExtra(EXTRA_THREAD, ConversationFragment.STUB_CONVERSATION);
            showFragmentNoAnimate(ConversationFragment.newInstance(mThreadId, false, mMetadata),
                    ConversationFragment.TAG);
            checkNetworkConnectivityState();
            registerRecognitionReceiver();

        } else {
            // Fallback for no action case. Typically should never happen
            throw new IllegalStateException(
                    "Please provide correct intent action to launch conversation activity.");
        }
    }

    private void createConversationWithPhrase(@Nullable final String phrase) {
        registerCreateConversationReceiver();
        MessagingService.createConversation(this, phrase);
    }

    private void registerCreateConversationReceiver() {
        mCreateConversationReceiver = new CreateConversationBroadcastReceiver(this);
        mCreateConversationReceiver.subscribe(this);
    }

    @Override
    public void onConversationCreated(final long threadId, @Nullable final Long messageId,
            @Nullable final Long memberId) {
        unregisterCreateConversationReceiver();

        mThreadId = threadId;
        registerRecognitionReceiver();

        mRecognitionStarted = true;
        autoStartRecognition();

        if (messageId != null && memberId != null) {
            showFragmentNoAnimateAllowingStateLoss(
                    ZoomedMessagesFragment.newInstance(threadId, messageId, memberId, mMetadata),
                    ZoomedMessagesFragment.TAG);
        } else {
            showFragmentNoAnimateAllowingStateLoss(ConversationFragment.newInstance(threadId, true, mMetadata),
                    ConversationFragment.TAG);
            checkNetworkConnectivityState();
        }
    }

    private void registerRecognitionReceiver() {
        mRecognitionReceiver = new RecognitionBroadcastReceiver(mThreadId, this);
        mRecognitionReceiver.subscribe(this);
    }

    @Override
    public void onConversationCreateError(final int kind) {
        unregisterCreateConversationReceiver();
        showFragmentNoAnimateAllowingStateLoss(
                ConversationFragment.newInstance(ConversationFragment.STUB_CONVERSATION, false, mMetadata),
                ConversationFragment.TAG);
        checkNetworkConnectivityState();
        // TODO: onConversationCreateError
    }

    private void unregisterCreateConversationReceiver() {
        if (mCreateConversationReceiver != null) {
            mCreateConversationReceiver.unsubscribe(this);
            mCreateConversationReceiver = null;
        }
    }

    @Override
    public void onSpeechKitInitialized() {
        mSpeechKitInitialized = true;
        mHasNetworkError = false;
        mMicrophoneBarView.setState(MicrophoneBarController.STATE_IDLE);
        autoStartRecognition();
    }

    @Override
    public void onMessageClick(final long threadId, final long messageId, final long memberId) {
        showFragment(ZoomedMessagesFragment.newInstance(threadId, messageId, memberId, mMetadata),
                ZoomedMessagesFragment.TAG);
    }

    @Override
    public void onPhraseRecognized(@NonNull final String phrase) {
        mMicrophoneBarView.showMessage(getString(R.string.phrase_recognized));
    }

    @Override
    public void onExitFullscreenClick(final long threadId) {
        if (switchToFragment(ConversationFragment.TAG) == null) {
            showFragment(ConversationFragment.newInstance(threadId, false, mMetadata), ConversationFragment.TAG,
                    /* addToBackStack */ true, /* clearBackStack */ true, /* animate */ true,
                    /* allow state loss */ false);
            checkNetworkConnectivityState();
        }
    }

    private void checkNetworkConnectivityState() {
        if (!NetworkUtils.isNetworkConnectedOrConnecting(this) && !mSpeechKitInitialized) {
            mHasNetworkError = true;
            onSpeechKitNetworkError();
        }
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case R.id.home:
        case android.R.id.home:
            onBackPressed();
            return true;

        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void autoStartRecognition() {
        if (mSpeechKitInitialized && mRecognitionStarted && isActivityResumed()) {
            mRecognitionStarted = true;
            mMicrophoneBarView.setState(MicrophoneBarController.STATE_IN_PROGRESS);
            MessagingService.startRecognition(this, mThreadId);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        mNetworkChangesReceiver.subscribe(this);
        autoStartRecognition();
    }

    @Override
    public void onMicrophoneClicked(final MicrophoneBarController controller,
            @MicrophoneBarController.State final int state) {
        switch (state) {
        case MicrophoneBarController.STATE_IDLE:
        case MicrophoneBarController.STATE_STOPPING:
            mRecognitionStarted = true;
            mMicrophoneBarView.setState(MicrophoneBarController.STATE_IN_PROGRESS);
            MessagingService.startRecognition(this, mThreadId);
            break;

        case MicrophoneBarController.STATE_IN_PROGRESS:
        case MicrophoneBarController.STATE_RECORDING:
            mRecognitionStarted = false;
            mMicrophoneBarView.setState(MicrophoneBarController.STATE_STOPPING);
            MessagingService.stopRecognition(this);
            break;
        }
    }

    @Override
    public void onRecognitionStarted(final boolean resumedAfterPlaying) {
        mHasNetworkError = false;

        mMicrophoneBarView.setKeepScreenOn(true);
        mMicrophoneBarView.setState(MicrophoneBarController.STATE_RECORDING);
        if (resumedAfterPlaying) {
            mMicrophoneBarView.showMessage("");
        }
    }

    @Override
    public void onPowerUpdate(final float power) {
        mMicrophoneBarView.setVolume(power);
    }

    @Override
    public void onError(final Error error) {
        mMicrophoneBarView.setState(MicrophoneBarController.STATE_IDLE);
        if (error.getCode() == Error.ERROR_NETWORK) {
            mHasNetworkError = true;
            mMicrophoneBarView.showMessage("");
            onSpeechKitNetworkError();
        } else {
            mMicrophoneBarView.showErrorMessage(getString(ErrorResolver.resolveError(error)));
        }
        mMicrophoneBarView.setKeepScreenOn(false);
    }

    @Override
    public void onNetworkStateChanged(@Nullable final NetworkInfo networkInfo) {
        if (NetworkUtils.isNetworkConnected(networkInfo)) {
            if (mRecognitionStarted && mHasNetworkError) {
                mMicrophoneBarView.setState(MicrophoneBarController.STATE_RECORDING);
                MessagingService.startRecognition(this, mThreadId);
            }
            mHasNetworkError = false;
        }
    }

    @Override
    public void onRecognitionDone(final boolean willStartPlaying) {
        mHasNetworkError = false;
        mMicrophoneBarView.setKeepScreenOn(false);
        if (willStartPlaying) {
            mMicrophoneBarView.setState(MicrophoneBarController.STATE_IDLE);
        } else {
            mMicrophoneBarView.setState(MicrophoneBarController.STATE_STOPPING);
        }
    }

    private void onSpeechKitNetworkError() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        if (fragmentManager.findFragmentByTag(NoConnectionDialogFragment.TAG) == null) {
            final NoConnectionDialogFragment dialog = NoConnectionDialogFragment.newInstance();
            dialog.show(fragmentManager, NoConnectionDialogFragment.TAG);
        }
    }

    @Override
    public void onPause() {
        mNetworkChangesReceiver.unsubscribe(this);
        MessagingService.stopRecognition(this);
        super.onPause();
    }

    @Override
    protected void onSaveInstanceState(final Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(KEY_HAS_CREATE_CONVERSATION_RECEIVER, mCreateConversationReceiver != null);
        outState.putBoolean(KEY_START_RECOGNITION, mRecognitionStarted);
        outState.putParcelable(KEY_METADATA, mMetadata);
        outState.putLong(KEY_THREAD, mThreadId);
        outState.putBoolean(KEY_HAS_NETWORK_ERROR, mHasNetworkError);
    }

    @Override
    protected void onDestroy() {
        mSpeechKitReceiver.unsubscribe(this);
        unregisterRecognitionReceiver();
        unregisterCreateConversationReceiver();
        super.onDestroy();
    }

    private void unregisterRecognitionReceiver() {
        if (mRecognitionReceiver != null) {
            mRecognitionReceiver.unsubscribe(this);
        }
    }

    @Override
    public void finish() {
        MessagingService.clearEmptyConversations(this);
        super.finish();
    }

}