Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ecef333 authored by Fan Zhang's avatar Fan Zhang
Browse files

Refactor Utils.startWithFragment to SubSettingLauncher

- Use the new launcher in AccountTypePrefernce for now. Will migrate the
  rest in follow up CLs.

Change-Id: I67aa49f54b39ecea4ecfdc32ccbd827d21fc79b8
Bug: 73250851
Test: robotest
parent 49c8080a
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -6319,13 +6319,6 @@
    <!-- Applicaitons with restrictions - settings button [CHAR LIMIT=30] -->
    <string name="apps_with_restrictions_settings_button">Expand settings for application</string>
    <!-- Warning message when changing a global setting for a tablet.[CHAR LIMIT=none] -->
    <string name="global_change_warning" product="tablet">This setting affects all users on this tablet.</string>
    <!-- Warning message when changing a global setting for a phone.[CHAR LIMIT=none] -->
    <string name="global_change_warning" product="default">This setting affects all users on this phone.</string>
    <!-- Warning message title for global locale change [CHAR LIMIT=40] -->
    <string name="global_locale_change_title">Change language</string>
    <!-- NFC payment settings --><skip/>
    <string name="nfc_payment_settings_title">Tap &amp; pay</string>
    <!-- Caption for button linking to a page explaining how Tap and Pay works-->
+0 −44
Original line number Diff line number Diff line
@@ -23,9 +23,7 @@ import static android.text.format.DateUtils.FORMAT_SHOW_DATE;

import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.Dialog;
import android.app.Fragment;
import android.app.IActivityManager;
import android.app.KeyguardManager;
@@ -34,7 +32,6 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
@@ -52,9 +49,6 @@ import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager;
import android.icu.text.RelativeDateTimeFormatter;
import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
import android.icu.util.ULocale;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
@@ -107,7 +101,6 @@ import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.FingerprintManagerWrapper;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;

import com.android.settingslib.utils.StringUtil;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Iterator;
@@ -237,16 +230,6 @@ public final class Utils extends com.android.settingslib.Utils {
        return null;
    }

    /**
     * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style
     * addresses.
     * @return the formatted and newline-separated IP addresses, or null if none.
     */
    public static String getDefaultIpAddresses(ConnectivityManager cm) {
        LinkProperties prop = cm.getActiveLinkProperties();
        return formatIpAddresses(prop);
    }

    private static String formatIpAddresses(LinkProperties prop) {
        if (prop == null) return null;
        Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
@@ -400,23 +383,6 @@ public final class Utils extends com.android.settingslib.Utils {
        }
    }

    /** Not global warming, it's global change warning. */
    public static Dialog buildGlobalChangeWarningDialog(final Context context, int titleResId,
            final Runnable positiveAction) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(titleResId);
        builder.setMessage(R.string.global_change_warning);
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                positiveAction.run();
            }
        });
        builder.setNegativeButton(android.R.string.cancel, null);

        return builder.create();
    }

    public static boolean hasMultipleUsers(Context context) {
        return ((UserManager) context.getSystemService(Context.USER_SERVICE))
                .getUsers().size() > 1;
@@ -477,20 +443,11 @@ public final class Utils extends com.android.settingslib.Utils {
     * @param resultTo Option fragment that should receive the result of the activity launch.
     * @param resultRequestCode If resultTo is non-null, this is the request code in which
     *                          to report the result.
     * @param titleResPackageName Optional package name for the resource id of the title.
     * @param titleResId resource id for the String to display for the title of this set
     *                   of preferences.
     * @param title String to display for the title of this set of preferences.
     * @param metricsCategory The current metricsCategory for logging source when fragment starts
     */
    public static void startWithFragment(Context context, String fragmentName, Bundle args,
            Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
            CharSequence title, int metricsCategory) {
        startWithFragment(context, fragmentName, args, resultTo, resultRequestCode,
                titleResPackageName, titleResId, title, false /* not a shortcut */,
                metricsCategory);
    }

    public static void startWithFragment(Context context, String fragmentName, Bundle args,
            Fragment resultTo, int resultRequestCode, int titleResId,
            CharSequence title, boolean isShortcut, int metricsCategory) {
@@ -511,7 +468,6 @@ public final class Utils extends com.android.settingslib.Utils {
                Intent.FLAG_ACTIVITY_NEW_TASK);
    }


    public static void startWithFragment(Context context, String fragmentName, Bundle args,
            Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
            CharSequence title, boolean isShortcut, int metricsCategory, int flags) {
+12 −7
Original line number Diff line number Diff line
@@ -28,11 +28,13 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;

import com.android.settings.Utils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.widget.AppPreference;

public class AccountTypePreference extends AppPreference implements OnPreferenceClickListener {
    /**
     * Title of the tile that is shown to the user.
     *
     * @attr ref android.R.styleable#PreferenceHeader_title
     */
    private final CharSequence mTitle;
@@ -56,6 +58,7 @@ public class AccountTypePreference extends AppPreference implements OnPreference
    /**
     * Full class name of the fragment to display when this tile is
     * selected.
     *
     * @attr ref android.R.styleable#PreferenceHeader_fragment
     */
    private final String mFragment;
@@ -101,10 +104,12 @@ public class AccountTypePreference extends AppPreference implements OnPreference
                    user.getIdentifier())) {
                return true;
            }
            Utils.startWithFragment(getContext(), mFragment, mFragmentArguments,
                null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName,
                mTitleResId, null /* title */,false /* isShortCut */, mMetricsCategory,
                    0 /* flag */);
            new SubSettingLauncher(getContext())
                    .setDestination(mFragment)
                    .setArguments(mFragmentArguments)
                    .setTitle(mTitleResPackageName, mTitleResId)
                    .setSourceMetricsCategory(mMetricsCategory)
                    .launch();
            return true;
        }
        return false;
+160 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.settings.core;

import android.annotation.StringRes;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;

import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;

public class SubSettingLauncher {

    private final Context mContext;
    private final LaunchRequest mLaunchRequest;
    private boolean mLaunched;

    public SubSettingLauncher(Context context) {
        if (context == null) {
            throw new IllegalArgumentException("Context must be non-null.");
        }
        mContext = context;
        mLaunchRequest = new LaunchRequest();
    }

    public SubSettingLauncher setDestination(String fragmentName) {
        mLaunchRequest.destinationName = fragmentName;
        return this;
    }

    public SubSettingLauncher setTitle(@StringRes int titleResId) {
        return setTitle(null /*titlePackageName*/, titleResId);
    }

    public SubSettingLauncher setTitle(String titlePackageName, @StringRes int titleResId) {
        mLaunchRequest.titleResPackageName = titlePackageName;
        mLaunchRequest.titleResId = titleResId;
        mLaunchRequest.title = null;
        return this;
    }

    public SubSettingLauncher setTitle(CharSequence title) {
        mLaunchRequest.title = title;
        return this;
    }

    public SubSettingLauncher setIsShortCut(boolean isShortCut) {
        mLaunchRequest.isShortCut = isShortCut;
        return this;
    }

    public SubSettingLauncher setArguments(Bundle arguments) {
        mLaunchRequest.arguments = arguments;
        return this;
    }

    public SubSettingLauncher setSourceMetricsCategory(int sourceMetricsCategory) {
        mLaunchRequest.sourceMetricsCategory = sourceMetricsCategory;
        return this;
    }

    public SubSettingLauncher setResultListener(Fragment listener, int resultRequestCode) {
        mLaunchRequest.mRequestCode = resultRequestCode;
        mLaunchRequest.mResultListener = listener;
        return this;
    }

    public SubSettingLauncher addFlags(int flags) {
        mLaunchRequest.flags |= flags;
        return this;
    }

    public SubSettingLauncher setUserHandle(UserHandle userHandle) {
        mLaunchRequest.userHandle = userHandle;
        return this;
    }

    public void launch() {
        if (mLaunched) {
            throw new IllegalStateException(
                    "This launcher has already been executed. Do not reuse");
        }
        mLaunched = true;
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setClass(mContext, SubSettings.class);

        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName);
        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.arguments);
        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
                mLaunchRequest.titleResPackageName);
        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
                mLaunchRequest.titleResId);
        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, mLaunchRequest.title);
        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT,
                mLaunchRequest.isShortCut);
        intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
                mLaunchRequest.sourceMetricsCategory);
        intent.addFlags(mLaunchRequest.flags);

        if (mLaunchRequest.userHandle != null
                && mLaunchRequest.userHandle.getIdentifier() != UserHandle.myUserId()) {
            launchAsUser(mContext, intent, mLaunchRequest.userHandle);
        } else if (mLaunchRequest.mResultListener != null) {
            launchForResult(mLaunchRequest.mResultListener, intent, mLaunchRequest.mRequestCode);
        } else {
            launch(intent);
        }
    }

    @VisibleForTesting
    void launch(Intent intent) {
        mContext.startActivity(intent);
    }

    private static void launchForResult(Fragment listener, Intent intent, int requestCode) {
        listener.getActivity().startActivityForResult(intent, requestCode);
    }

    private static void launchAsUser(Context context, Intent intent, UserHandle userHandle) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivityAsUser(intent, userHandle);
    }

    /**
     * Simple container that has information about how to launch a subsetting.
     */
    static class LaunchRequest {
        String destinationName;
        int titleResId;
        String titleResPackageName;
        CharSequence title;
        boolean isShortCut;
        int sourceMetricsCategory;
        int flags;
        Fragment mResultListener;
        int mRequestCode;
        UserHandle userHandle;
        Bundle arguments;
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.settings.core;

import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.Intent;

import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SubSettingLauncherTest {

    private Context mContext;

    @Before
    public void setUp() {
        mContext = RuntimeEnvironment.application;
    }

    @Test(expected = IllegalStateException.class)
    public void cannotReuseLauncher() {
        final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext));
        doNothing().when(launcher).launch(any(Intent.class));
        launcher.launch();
        launcher.launch();
    }

    @Test
    public void launch_shouldIncludeAllParams() {
        final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
        final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext));
        launcher.setTitle("123")
                .setDestination(SubSettingLauncherTest.class.getName())
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                .launch();
        doNothing().when(launcher).launch(any(Intent.class));
        verify(launcher).launch(intentArgumentCaptor.capture());
        final Intent intent = intentArgumentCaptor.getValue();

        assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE))
                .isEqualTo("123");
        assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
                .isEqualTo(SubSettingLauncherTest.class.getName());
        assertThat(intent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK);
    }
}