Files
packages_apps_Messaging/src/com/android/messaging/ui/conversation/ConversationActivity.java
Cole Faust 50b73ca58a Fix errorprone warnings that should be errors
This commit is part of a large scale change to fix errorprone
errors that have been downgraded to warnings in the android
source tree, so that they can be promoted to errors again.
The full list of changes include the following, but not all
will be present in any one individual commit:

BadAnnotationImplementation
BadShiftAmount
BanJNDI
BoxedPrimitiveEquality
ComparableType
ComplexBooleanConstant
CollectionToArraySafeParameter
ConditionalExpressionNumericPromotion
DangerousLiteralNull
DoubleBraceInitialization
DurationFrom
DurationTemporalUnit
EmptyTopLevelDeclaration
EqualsNull
EqualsReference
FormatString
FromTemporalAccessor
GetClassOnAnnotation
GetClassOnClass
HashtableContains
IdentityBinaryExpression
IdentityHashMapBoxing
InstantTemporalUnit
InvalidTimeZoneID
InvalidZoneId
IsInstanceIncompatibleType
JUnitParameterMethodNotFound
LockOnBoxedPrimitive
MathRoundIntLong
MislabeledAndroidString
MisusedDayOfYear
MissingSuperCall
MisusedWeekYear
ModifyingCollectionWithItself
NoCanIgnoreReturnValueOnClasses
NonRuntimeAnnotation
NullableOnContainingClass
NullTernary
OverridesJavaxInjectableMethod
ParcelableCreator
PeriodFrom
PreconditionsInvalidPlaceholder
ProtoBuilderReturnValueIgnored
ProtoFieldNullComparison
RandomModInteger
RectIntersectReturnValueIgnored
ReturnValueIgnored
SelfAssignment
SelfComparison
SelfEquals
SizeGreaterThanOrEqualsZero
StringBuilderInitWithChar
TreeToString
TryFailThrowable
UnnecessaryCheckNotNull
UnusedCollectionModifiedInPlace
XorPower

See https://errorprone.info/bugpatterns for more
information on the checks.

Bug: 253827323
Test: m RUN_ERROR_PRONE=true javac-check
Change-Id: I8b1533cbea835343dcf589cbaa57c63794be58bd
2022-10-15 21:33:28 -07:00

381 lines
15 KiB
Java

/*
* 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.messaging.ui.conversation;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import android.text.TextUtils;
import android.view.MenuItem;
import com.android.messaging.R;
import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.datamodel.data.MessageData;
import com.android.messaging.ui.BugleActionBarActivity;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.ui.contact.ContactPickerFragment;
import com.android.messaging.ui.contact.ContactPickerFragment.ContactPickerFragmentHost;
import com.android.messaging.ui.conversation.ConversationActivityUiState.ConversationActivityUiStateHost;
import com.android.messaging.ui.conversation.ConversationFragment.ConversationFragmentHost;
import com.android.messaging.ui.conversationlist.ConversationListActivity;
import com.android.messaging.util.Assert;
import com.android.messaging.util.ContentType;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.OsUtil;
import com.android.messaging.util.UiUtils;
public class ConversationActivity extends BugleActionBarActivity
implements ContactPickerFragmentHost, ConversationFragmentHost,
ConversationActivityUiStateHost {
public static final int FINISH_RESULT_CODE = 1;
private static final String SAVED_INSTANCE_STATE_UI_STATE_KEY = "uistate";
private ConversationActivityUiState mUiState;
// Fragment transactions cannot be performed after onSaveInstanceState() has been called since
// it will cause state loss. We don't want to call commitAllowingStateLoss() since it's
// dangerous. Therefore, we note when instance state is saved and avoid performing UI state
// updates concerning fragments past that point.
private boolean mInstanceStateSaved;
// Tracks whether onPause is called.
private boolean mIsPaused;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.conversation_activity);
final Intent intent = getIntent();
// Do our best to restore UI state from saved instance state.
if (savedInstanceState != null) {
mUiState = savedInstanceState.getParcelable(SAVED_INSTANCE_STATE_UI_STATE_KEY);
} else {
if (intent.
getBooleanExtra(UIIntents.UI_INTENT_EXTRA_GOTO_CONVERSATION_LIST, false)) {
// See the comment in BugleWidgetService.getViewMoreConversationsView() why this
// is unfortunately necessary. The Bugle desktop widget can display a list of
// conversations. When there are more conversations that can be displayed in
// the widget, the last item is a "More conversations" item. The way widgets
// are built, the list items can only go to a single fill-in intent which points
// to this ConversationActivity. When the user taps on "More conversations", we
// really want to go to the ConversationList. This code makes that possible.
finish();
final Intent convListIntent = new Intent(this, ConversationListActivity.class);
convListIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(convListIntent);
return;
}
}
// If saved instance state doesn't offer a clue, get the info from the intent.
if (mUiState == null) {
final String conversationId = intent.getStringExtra(
UIIntents.UI_INTENT_EXTRA_CONVERSATION_ID);
mUiState = new ConversationActivityUiState(conversationId);
}
mUiState.setHost(this);
mInstanceStateSaved = false;
// Don't animate UI state change for initial setup.
updateUiState(false /* animate */);
// See if we're getting called from a widget to directly display an image or video
final String extraToDisplay =
intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_ATTACHMENT_URI);
if (!TextUtils.isEmpty(extraToDisplay)) {
final String contentType =
intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_ATTACHMENT_TYPE);
final Rect bounds = UiUtils.getMeasuredBoundsOnScreen(
findViewById(R.id.conversation_and_compose_container));
if (ContentType.isImageType(contentType)) {
final Uri imagesUri = MessagingContentProvider.buildConversationImagesUri(
mUiState.getConversationId());
UIIntents.get().launchFullScreenPhotoViewer(
this, Uri.parse(extraToDisplay), bounds, imagesUri);
} else if (ContentType.isVideoType(contentType)) {
UIIntents.get().launchFullScreenVideoViewer(this, Uri.parse(extraToDisplay));
}
}
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
// After onSaveInstanceState() is called, future changes to mUiState won't update the UI
// anymore, because fragment transactions are not allowed past this point.
// For an activity recreation due to orientation change, the saved instance state keeps
// using the in-memory copy of the UI state instead of writing it to parcel as an
// optimization, so the UI state values may still change in response to, for example,
// focus change from the framework, making mUiState and actual UI inconsistent.
// Therefore, save an exact "snapshot" (clone) of the UI state object to make sure the
// restored UI state ALWAYS matches the actual restored UI components.
outState.putParcelable(SAVED_INSTANCE_STATE_UI_STATE_KEY, mUiState.clone());
mInstanceStateSaved = true;
}
@Override
protected void onResume() {
super.onResume();
// we need to reset the mInstanceStateSaved flag since we may have just been restored from
// a previous onStop() instead of an onDestroy().
mInstanceStateSaved = false;
mIsPaused = false;
}
@Override
protected void onPause() {
super.onPause();
mIsPaused = true;
}
@Override
public void onWindowFocusChanged(final boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
final ConversationFragment conversationFragment = getConversationFragment();
// When the screen is turned on, the last used activity gets resumed, but it gets
// window focus only after the lock screen is unlocked.
if (hasFocus && conversationFragment != null) {
conversationFragment.setConversationFocus();
}
}
@Override
public void onDisplayHeightChanged(final int heightSpecification) {
super.onDisplayHeightChanged(heightSpecification);
invalidateActionBar();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mUiState != null) {
mUiState.setHost(null);
}
}
@Override
public void updateActionBar(final ActionBar actionBar) {
super.updateActionBar(actionBar);
final ConversationFragment conversation = getConversationFragment();
final ContactPickerFragment contactPicker = getContactPicker();
if (contactPicker != null && mUiState.shouldShowContactPickerFragment()) {
contactPicker.updateActionBar(actionBar);
} else if (conversation != null && mUiState.shouldShowConversationFragment()) {
conversation.updateActionBar(actionBar);
}
}
@Override
public boolean onOptionsItemSelected(final MenuItem menuItem) {
if (super.onOptionsItemSelected(menuItem)) {
return true;
}
if (menuItem.getItemId() == android.R.id.home) {
onNavigationUpPressed();
return true;
}
return false;
}
public void onNavigationUpPressed() {
// Let the conversation fragment handle the navigation up press.
final ConversationFragment conversationFragment = getConversationFragment();
if (conversationFragment != null && conversationFragment.onNavigationUpPressed()) {
return;
}
onFinishCurrentConversation();
}
@Override
public void onBackPressed() {
// If action mode is active dismiss it
if (getActionMode() != null) {
dismissActionMode();
return;
}
// Let the conversation fragment handle the back press.
final ConversationFragment conversationFragment = getConversationFragment();
if (conversationFragment != null && conversationFragment.onBackPressed()) {
return;
}
super.onBackPressed();
}
private ContactPickerFragment getContactPicker() {
return (ContactPickerFragment) getFragmentManager().findFragmentByTag(
ContactPickerFragment.FRAGMENT_TAG);
}
private ConversationFragment getConversationFragment() {
return (ConversationFragment) getFragmentManager().findFragmentByTag(
ConversationFragment.FRAGMENT_TAG);
}
@Override // From ContactPickerFragmentHost
public void onGetOrCreateNewConversation(final String conversationId) {
Assert.isTrue(conversationId != null);
mUiState.onGetOrCreateConversation(conversationId);
}
@Override // From ContactPickerFragmentHost
public void onBackButtonPressed() {
onBackPressed();
}
@Override // From ContactPickerFragmentHost
public void onInitiateAddMoreParticipants() {
mUiState.onAddMoreParticipants();
}
@Override
public void onParticipantCountChanged(final boolean canAddMoreParticipants) {
mUiState.onParticipantCountUpdated(canAddMoreParticipants);
}
@Override // From ConversationFragmentHost
public void onStartComposeMessage() {
mUiState.onStartMessageCompose();
}
@Override // From ConversationFragmentHost
public void onConversationMetadataUpdated() {
invalidateActionBar();
}
@Override // From ConversationFragmentHost
public void onConversationMessagesUpdated(final int numberOfMessages) {
}
@Override // From ConversationFragmentHost
public void onConversationParticipantDataLoaded(final int numberOfParticipants) {
}
@Override // From ConversationFragmentHost
public boolean isActiveAndFocused() {
return !mIsPaused && hasWindowFocus();
}
@Override // From ConversationActivityUiStateListener
public void onConversationContactPickerUiStateChanged(final int oldState, final int newState,
final boolean animate) {
Assert.isTrue(oldState != newState);
updateUiState(animate);
}
private void updateUiState(final boolean animate) {
if (mInstanceStateSaved || mIsPaused) {
return;
}
Assert.notNull(mUiState);
final Intent intent = getIntent();
final String conversationId = mUiState.getConversationId();
final FragmentManager fragmentManager = getFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
final boolean needConversationFragment = mUiState.shouldShowConversationFragment();
final boolean needContactPickerFragment = mUiState.shouldShowContactPickerFragment();
ConversationFragment conversationFragment = getConversationFragment();
// Set up the conversation fragment.
if (needConversationFragment) {
Assert.notNull(conversationId);
if (conversationFragment == null) {
conversationFragment = new ConversationFragment();
fragmentTransaction.add(R.id.conversation_fragment_container,
conversationFragment, ConversationFragment.FRAGMENT_TAG);
}
final MessageData draftData = intent.getParcelableExtra(
UIIntents.UI_INTENT_EXTRA_DRAFT_DATA);
if (!needContactPickerFragment) {
// Once the user has committed the audience,remove the draft data from the
// intent to prevent reuse
intent.removeExtra(UIIntents.UI_INTENT_EXTRA_DRAFT_DATA);
}
conversationFragment.setHost(this);
conversationFragment.setConversationInfo(this, conversationId, draftData);
} else if (conversationFragment != null) {
// Don't save draft to DB when removing conversation fragment and switching to
// contact picking mode. The draft is intended for the new group.
conversationFragment.suppressWriteDraft();
fragmentTransaction.remove(conversationFragment);
}
// Set up the contact picker fragment.
ContactPickerFragment contactPickerFragment = getContactPicker();
if (needContactPickerFragment) {
if (contactPickerFragment == null) {
contactPickerFragment = new ContactPickerFragment();
fragmentTransaction.add(R.id.contact_picker_fragment_container,
contactPickerFragment, ContactPickerFragment.FRAGMENT_TAG);
}
contactPickerFragment.setHost(this);
contactPickerFragment.setContactPickingMode(mUiState.getDesiredContactPickingMode(),
animate);
} else if (contactPickerFragment != null) {
fragmentTransaction.remove(contactPickerFragment);
}
fragmentTransaction.commit();
invalidateActionBar();
}
@Override
public void onFinishCurrentConversation() {
// Simply finish the current activity. The current design is to leave any empty
// conversations as is.
if (OsUtil.isAtLeastL()) {
finishAfterTransition();
} else {
finish();
}
}
@Override
public boolean shouldResumeComposeMessage() {
return mUiState.shouldResumeComposeMessage();
}
@SuppressWarnings("MissingSuperCall") // TODO: fix me
@Override
protected void onActivityResult(final int requestCode, final int resultCode,
final Intent data) {
if (requestCode == ConversationFragment.REQUEST_CHOOSE_ATTACHMENTS &&
resultCode == RESULT_OK) {
final ConversationFragment conversationFragment = getConversationFragment();
if (conversationFragment != null) {
conversationFragment.onAttachmentChoosen();
} else {
LogUtil.e(LogUtil.BUGLE_TAG, "ConversationFragment is missing after launching " +
"AttachmentChooserActivity!");
}
} else if (resultCode == FINISH_RESULT_CODE) {
finish();
}
}
}