diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c2dcd158d12..4cdfa254e02 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3053,6 +3053,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4242609ec64..50cecfa5f29 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2338,6 +2338,10 @@
AndroidAP WPA2 PSK hotspotAndroidHotspot
+
+ Save this network?
+
+ %1$s would like to save a network to your phone
diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java
new file mode 100644
index 00000000000..0810b54a7fa
--- /dev/null
+++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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.wifi.addappnetworks;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.core.HideNonSystemOverlayMixin;
+
+/**
+ * When apps send a new intent with a WifiConfiguration list extra to Settings APP. Settings APP
+ * will launch this activity, which contains {@code AddAppNetworksFragment}, with a UI panel pop
+ * up asking the user if they approve the network being proposed by the app to be saved on to
+ * the device. User can decide to save or cancel the request.,
+ */
+public class AddAppNetworksActivity extends FragmentActivity {
+ public static final String TAG = "AddAppNetworksActivity";
+
+ private AddAppNetworksFragment mFragment;
+
+ /** Key specifying the package name of the apps which requested the Panel. */
+ public static final String KEY_CALLING_PACKAGE_NAME = "panel_calling_package_name";
+
+ @VisibleForTesting
+ final Bundle mBundle = new Bundle();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.settings_panel);
+ showAddNetworksFragment();
+ getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ showAddNetworksFragment();
+ }
+
+ @VisibleForTesting
+ void showAddNetworksFragment() {
+ // Move the window to the bottom of screen, and make it take up the entire screen width.
+ final Window window = getWindow();
+ window.setGravity(Gravity.BOTTOM);
+ window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.WRAP_CONTENT);
+
+ // TODO: check the new intent status
+ mBundle.putString(KEY_CALLING_PACKAGE_NAME, getCallingPackage());
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ if (fragmentManager.findFragmentByTag(TAG) == null) {
+ final AddAppNetworksFragment fragment = new AddAppNetworksFragment();
+ fragment.setArguments(mBundle);
+ fragmentManager.beginTransaction().add(R.id.main_content, fragment, TAG).commit();
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
new file mode 100644
index 00000000000..281ca5780fe
--- /dev/null
+++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 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.wifi.addappnetworks;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.InstrumentedFragment;
+
+import java.util.ArrayList;
+
+/**
+ * The Fragment list those networks, which is proposed by other app, to user, and handle user's
+ * choose on either saving those networks or rejecting the request.
+ */
+public class AddAppNetworksFragment extends InstrumentedFragment {
+ public static final String TAG = "AddAppNetworksFragment";
+
+ private TextView mTitleView;
+ private TextView mSummaryView;
+ private ImageView mIconView;
+
+ @VisibleForTesting
+ Button mCancelButton;
+ @VisibleForTesting
+ Button mSaveButton;
+ @VisibleForTesting
+ String mCallingPackageName;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.wifi_add_app_networks, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ // init local variable.
+ mTitleView = view.findViewById(R.id.app_title);
+ mIconView = view.findViewById(R.id.app_icon);
+ mCancelButton = view.findViewById(R.id.cancel);
+ mSaveButton = view.findViewById(R.id.save);
+ mSummaryView = view.findViewById(R.id.app_summary);
+
+ // Assigns button listeners.
+ mCancelButton.setOnClickListener(getCancelListener());
+ mSaveButton.setOnClickListener(getSaveListener());
+
+ final Bundle bundle = getArguments();
+ createContent(bundle);
+ }
+
+ private void createContent(Bundle bundle) {
+ final FragmentActivity activity = getActivity();
+
+ // Assigns caller app icon and summary.
+ mCallingPackageName =
+ bundle.getString(AddAppNetworksActivity.KEY_CALLING_PACKAGE_NAME);
+ assignAppIcon(activity, mCallingPackageName);
+ assignTitleAndSummary(activity, mCallingPackageName);
+ }
+
+ private void assignAppIcon(Context context, String callingPackageName) {
+ final Drawable drawable = loadPackageIconDrawable(context, callingPackageName);
+ mIconView.setImageDrawable(drawable);
+ }
+
+ private Drawable loadPackageIconDrawable(Context context, String callingPackageName) {
+ Drawable icon = null;
+ try {
+ icon = context.getPackageManager().getApplicationIcon(callingPackageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Cannot get application icon", e);
+ }
+
+ return icon;
+ }
+
+ private void assignTitleAndSummary(Context context, String callingPackageName) {
+ // Assigns caller app name to title
+ mTitleView.setText(getTitle());
+
+ // Set summary
+ mSummaryView.setText(getAddNetworkRequesterSummary(
+ Utils.getApplicationLabel(context, callingPackageName)));
+ }
+
+ private CharSequence getAddNetworkRequesterSummary(CharSequence appName) {
+ return getString(R.string.wifi_add_app_single_network_summary, appName);
+ }
+
+ private CharSequence getTitle() {
+ return getString(R.string.wifi_add_app_single_network_title);
+ }
+
+ View.OnClickListener getCancelListener() {
+ return (v) -> {
+ Log.d(TAG, "User rejected to add network");
+ };
+ }
+
+ View.OnClickListener getSaveListener() {
+ return (v) -> {
+ Log.d(TAG, "User agree to add networks");
+ };
+ }
+
+ private void finishWithResult(int resultCode, ArrayList resultArrayList) {
+ if (resultArrayList != null) {
+ Intent intent = new Intent();
+ intent.putIntegerArrayListExtra(Settings.EXTRA_WIFI_CONFIGURATION_RESULT_LIST,
+ resultArrayList);
+ getActivity().setResult(resultCode, intent);
+ }
+ getActivity().finish();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO(b/144891278): Need to define a new metric for this page, use the WIFI item first.
+ return SettingsEnums.WIFI;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java
new file mode 100644
index 00000000000..b6146985142
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivityTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.wifi.addappnetworks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AddAppNetworksActivityTest {
+
+ @Test
+ public void startActivity_withPackageName_bundleShouldHaveRightPackageName() {
+ final String packageName = RuntimeEnvironment.application.getPackageName();
+ final AddAppNetworksActivity activity =
+ Robolectric.buildActivity(AddAppNetworksActivity.class).create().get();
+ shadowOf(activity).setCallingPackage(packageName);
+
+ activity.showAddNetworksFragment();
+
+ assertThat(activity.mBundle.getString(AddAppNetworksActivity.KEY_CALLING_PACKAGE_NAME))
+ .isEqualTo(packageName);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
new file mode 100644
index 00000000000..38ddf335051
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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.wifi.addappnetworks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentActivity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
+
+@RunWith(RobolectricTestRunner.class)
+public class AddAppNetworksFragmentTest {
+ private static final String FAKE_APP_NAME = "fake_app_name";
+ private FragmentActivity mActivity;
+ private AddAppNetworksFragment mAddAppNetworksFragment;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mAddAppNetworksFragment = spy(new AddAppNetworksFragment());
+ MockitoAnnotations.initMocks(this);
+
+ // Set up bundle
+ final Bundle bundle = new Bundle();
+ bundle.putString(AddAppNetworksActivity.KEY_CALLING_PACKAGE_NAME, FAKE_APP_NAME);
+ doReturn(bundle).when(mAddAppNetworksFragment).getArguments();
+
+ FragmentController.setupFragment(mAddAppNetworksFragment);
+ }
+
+ @Test
+ public void callingPackageName_onCreateView_shouldBeCorrect() {
+ assertThat(mAddAppNetworksFragment.mCallingPackageName).isEqualTo(FAKE_APP_NAME);
+ }
+
+ @Test
+ public void launchFragment_shouldShowSaveButton() {
+ assertThat(mAddAppNetworksFragment.mSaveButton).isNotNull();
+ }
+
+ @Test
+ public void launchFragment_shouldShowCancelButton() {
+ assertThat(mAddAppNetworksFragment.mCancelButton).isNotNull();
+ }
+}