Merge "First commit for settings panels"

This commit is contained in:
Matthew Fritze
2018-11-27 17:34:22 +00:00
committed by Android (Google) Code Review
23 changed files with 613 additions and 13 deletions

View File

@@ -93,7 +93,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(), "toggle_airplane");
return true;
}
@Override

View File

@@ -29,6 +29,7 @@ import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.gestures.AssistGestureFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
@@ -105,6 +106,8 @@ public abstract class FeatureFactory {
public abstract AccountFeatureProvider getAccountFeatureProvider();
public abstract PanelFeatureProvider getPanelFeatureProvider();
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);

View File

@@ -42,6 +42,8 @@ import com.android.settings.gestures.AssistGestureFeatureProvider;
import com.android.settings.gestures.AssistGestureFeatureProviderImpl;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProviderImpl;
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.panel.PanelFeatureProviderImpl;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.security.SecurityFeatureProvider;
@@ -72,6 +74,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
private UserFeatureProvider mUserFeatureProvider;
private SlicesFeatureProvider mSlicesFeatureProvider;
private AccountFeatureProvider mAccountFeatureProvider;
private PanelFeatureProvider mPanelFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -209,4 +212,12 @@ public class FeatureFactoryImpl extends FeatureFactory {
}
return mAccountFeatureProvider;
}
@Override
public PanelFeatureProvider getPanelFeatureProvider() {
if (mPanelFeatureProvider == null) {
mPanelFeatureProvider = new PanelFeatureProviderImpl();
}
return mPanelFeatureProvider;
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.panel;
import androidx.annotation.VisibleForTesting;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.SettingsSlicesContract;
import com.android.settings.R;
import com.android.settings.wifi.WifiSlice;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the Internet Connectivity Panel.
*
* <p>
* Displays Wifi (full Slice) and Airplane mode.
* </p>
*/
public class InternetConnectivityPanel implements PanelContent {
@VisibleForTesting
static final Uri AIRPLANE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSlicesContract.AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE)
.build();
private final Context mContext;
public static InternetConnectivityPanel create(Context context) {
return new InternetConnectivityPanel(context);
}
private InternetConnectivityPanel(Context context) {
mContext = context.getApplicationContext();
}
@Override
public String getTitle() {
return (String) mContext.getText(R.string.internet_connectivity_panel_title);
}
@Override
public List<Uri> getSlices() {
final List<Uri> uris = new ArrayList<>();
uris.add(WifiSlice.WIFI_URI);
uris.add(AIRPLANE_URI);
return uris;
}
@Override
public Intent getSeeMoreIntent() {
return null;
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.panel;
import android.content.Intent;
import android.net.Uri;
import java.util.List;
/**
* Represents the data class needed to create a Settings Panel. See {@link PanelFragment}.
*/
public interface PanelContent {
/**
* @return a string for the title of the Panel.
*/
CharSequence getTitle();
/**
* @return an ordered list of the Slices to be displayed in the Panel. The first item in the
* list is shown on top of the Panel.
*/
List<Uri> getSlices();
/**
* @return an {@link Intent} to the full content in Settings that is summarized by the Panel.
*
* <p>
* For example, for the connectivity panel you would intent to the Network & Internet page.
* </p>
*/
Intent getSeeMoreIntent();
}

View File

@@ -0,0 +1,27 @@
/*
* 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.panel;
import android.content.Context;
public interface PanelFeatureProvider {
/**
* Returns {@link PanelContent} as specified by the {@param panelType}.
*/
PanelContent getPanel(Context context, String panelType);
}

View File

@@ -0,0 +1,32 @@
/*
* 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.panel;
import android.content.Context;
public class PanelFeatureProviderImpl implements PanelFeatureProvider {
@Override
public PanelContent getPanel(Context context, String panelType) {
switch (panelType) {
case SettingsPanelActivity.PANEL_TYPE_WIFI:
return InternetConnectivityPanel.create(context);
}
throw new IllegalStateException("No matching panel for: " + panelType);
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.panel;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.lifecycle.LiveData;
import androidx.slice.Slice;
import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;
import com.android.settings.R;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.overlay.FeatureFactory;
import java.util.ArrayList;
import java.util.List;
public class PanelFragment extends Fragment {
private static final String TAG = "PanelFragment";
private List<SliceView> mSliceViewList;
private List<LiveData<Slice>> mSliceDataList;
private LinearLayout mPanelLayout;
public PanelFragment() {
mSliceViewList = new ArrayList<>();
mSliceDataList = new ArrayList<>();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final View view = inflater.inflate(R.layout.panel_layout, container, false);
mPanelLayout = view.findViewById(R.id.panel_parent_layout);
final Bundle arguments = getArguments();
final String panelType = arguments.getString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT);
final PanelContent panel = FeatureFactory.getFactory(activity)
.getPanelFeatureProvider()
.getPanel(activity, panelType);
activity.setTitle(panel.getTitle());
for (Uri uri : panel.getSlices()) {
final SliceView sliceView = new SliceView(activity);
mPanelLayout.addView(sliceView);
final LiveData<Slice> liveData = SliceLiveData.fromUri(activity, uri);
liveData.observe(this /* lifecycleOwner */, sliceView);
mSliceDataList.add(liveData);
mSliceViewList.add(sliceView);
}
return view;
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.panel;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
/**
* Dialog Activity to host Settings Slices.
*
* TODO link to action / framework API
*/
public class SettingsPanelActivity extends FragmentActivity {
private final String TAG = "panel_activity";
/**
* Key specifying which Panel the app is requesting.
*/
public static final String KEY_PANEL_TYPE_ARGUMENT = "PANEL_TYPE_ARGUMENT";
// TODO (b/117804442) move to framework
public static final String EXTRA_PANEL_TYPE = "com.android.settings.panel.extra";
// TODO (b/117804442) move to framework
public static final String PANEL_TYPE_WIFI = "wifi_panel";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ComponentName callingActivityName = getCallingActivity();
if (callingActivityName == null) {
Log.e(TAG, "Must start with startActivityForResult. Closing.");
finish();
return;
}
final Intent callingIntent = getIntent();
if (callingIntent == null) {
Log.e(TAG, "Null intent, closing Panel Activity");
finish();
return;
}
final String typeExtra = callingIntent.getStringExtra(EXTRA_PANEL_TYPE);
if (TextUtils.isEmpty(typeExtra)) {
Log.e(TAG, "No intent passed, closing Panel Activity");
return;
}
setContentView(R.layout.settings_panel);
// 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);
final Bundle bundle = new Bundle();
bundle.putString(KEY_PANEL_TYPE_ARGUMENT, typeExtra);
final PanelFragment panelFragment = new PanelFragment();
panelFragment.setArguments(bundle);
final FragmentManager fragmentManager = getSupportFragmentManager();
final Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
if (fragment == null) {
fragmentManager.beginTransaction().add(R.id.main_content, panelFragment).commit();
}
}
}

View File

@@ -427,7 +427,7 @@ public class SettingsSliceProvider extends SliceProvider {
try {
sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
} catch (IllegalStateException e) {
Log.d(TAG, "Could not create slicedata for uri: " + uri);
Log.d(TAG, "Could not create slicedata for uri: " + uri, e);
return;
}

View File

@@ -1,3 +1,19 @@
/*
* 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.slices;
import android.content.Context;