Quick and dirty UI for viewing app op information.

Change-Id: If17bfbe84cf438ca9bb37bf446564f39de99cee1
This commit is contained in:
Dianne Hackborn
2013-01-15 19:02:05 -08:00
parent 6001a7b0d4
commit a522a8ef82
9 changed files with 743 additions and 1 deletions

View File

@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := bouncycastle telephony-common LOCAL_JAVA_LIBRARIES := bouncycastle telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := guava android-support-v4 jsr305 LOCAL_STATIC_JAVA_LIBRARIES := guava android-support-v4 android-support-v13 jsr305
LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional

View File

@@ -768,6 +768,24 @@
android:resource="@id/application_settings" /> android:resource="@id/application_settings" />
</activity> </activity>
<activity android:name="Settings$AppOpsSummaryActivity"
android:label="@string/app_ops_settings"
android:taskAffinity=""
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.APP_OPS_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.AppOpsSummary" />
<!--
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/application_settings" /> -->
</activity>
<activity android:name="Settings$LocationSettingsActivity" <activity android:name="Settings$LocationSettingsActivity"
android:label="@string/location_settings_title" android:label="@string/location_settings_title"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2008, 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.
*/
-->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:columnCount="3">
<ImageView
android:id="@+id/app_icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_rowSpan="2"
android:layout_marginEnd="8dip"
android:scaleType="centerInside"
android:contentDescription="@null" />
<TextView
android:id="@+id/app_name"
android:layout_width="0dip"
android:layout_columnSpan="2"
android:layout_gravity="fill_horizontal"
android:layout_marginTop="2dip"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textAlignment="viewStart" />
<TextView
android:id="@+id/op_name"
android:layout_width="0dip"
android:layout_gravity="fill_horizontal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart" />
<TextView
android:id="@+id/op_time"
android:layout_marginStart="8dip"
android:textAppearance="?android:attr/textAppearanceSmall" />
</GridLayout>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, 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.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<android.support.v4.view.PagerTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textAppearance="@style/TextAppearance.PagerTabs"
android:paddingLeft="@dimen/pager_tabs_padding"
android:paddingRight="@dimen/pager_tabs_padding">
</android.support.v4.view.PagerTabStrip>
</android.support.v4.view.ViewPager>
</LinearLayout>

View File

@@ -548,6 +548,25 @@
<item>auto</item> <item>auto</item>
</string-array> </string-array>
<!-- Names of categories of app ops tabs -->
<string-array name="app_ops_categories">
<item>Location</item>
<item>Personal</item>
<item>Device</item>
</string-array>
<!-- User display names for app ops codes -->
<string-array name="app_ops_names">
<item>Coarse Location</item>
<item>Fine Location</item>
<item>GPS</item>
<item>Vibrate</item>
<item>Contacts: Read</item>
<item>Contacts: Write</item>
<item>Call Log: Read</item>
<item>Call Log: Write</item>
</string-array>
<!-- Titles for the list of long press timeout options. --> <!-- Titles for the list of long press timeout options. -->
<string-array name="long_press_timeout_selector_titles"> <string-array name="long_press_timeout_selector_titles">
<!-- A title for the option for short long-press timeout [CHAR LIMIT=25] --> <!-- A title for the option for short long-press timeout [CHAR LIMIT=25] -->

View File

@@ -2698,6 +2698,12 @@
If you turn off notifications for this app, you may miss important alerts and updates. If you turn off notifications for this app, you may miss important alerts and updates.
</string> </string>
<!-- App Ops Settings --> <skip />
<!-- [CHAR LIMIT=NONE] App ops settings title, on main settings screen. If clicked, the user is taken to a settings screen for app operations -->
<string name="app_ops_settings">App ops</string>
<!-- [CHAR LIMIT=NONE] Time label for an operation that is currently running. -->
<string name="app_ops_running">Running</string>
<!-- [CHAR LIMIT=25] Services settings screen, setting option name for the user to go to the screen to view app storage use --> <!-- [CHAR LIMIT=25] Services settings screen, setting option name for the user to go to the screen to view app storage use -->
<string name="storageuse_settings_title">Storage use</string> <string name="storageuse_settings_title">Storage use</string>
<!-- Services settings screen, setting option summary for the user to go to the screen to app storage use --> <!-- Services settings screen, setting option summary for the user to go to the screen to app storage use -->

View File

@@ -805,6 +805,7 @@ public class Settings extends PreferenceActivity
public static class DeviceInfoSettingsActivity extends Settings { /* empty */ } public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
public static class ApplicationSettingsActivity extends Settings { /* empty */ } public static class ApplicationSettingsActivity extends Settings { /* empty */ }
public static class ManageApplicationsActivity extends Settings { /* empty */ } public static class ManageApplicationsActivity extends Settings { /* empty */ }
public static class AppOpsSummaryActivity extends Settings { /* empty */ }
public static class StorageUseActivity extends Settings { /* empty */ } public static class StorageUseActivity extends Settings { /* empty */ }
public static class DevelopmentSettingsActivity extends Settings { /* empty */ } public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
public static class AccessibilitySettingsActivity extends Settings { /* empty */ } public static class AccessibilitySettingsActivity extends Settings { /* empty */ }

View File

@@ -0,0 +1,487 @@
package com.android.settings.applications;
import android.app.AppOpsManager;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.io.File;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import com.android.settings.R;
public class AppOpsCategory extends ListFragment implements
LoaderManager.LoaderCallbacks<List<AppOpsCategory.AppOpEntry>> {
// This is the Adapter being used to display the list's data.
AppListAdapter mAdapter;
/**
* This class holds the per-item data in our Loader.
*/
public static class AppEntry {
private final AppListLoader mLoader;
private final ApplicationInfo mInfo;
private final File mApkFile;
private String mLabel;
private Drawable mIcon;
private boolean mMounted;
public AppEntry(AppListLoader loader, ApplicationInfo info) {
mLoader = loader;
mInfo = info;
mApkFile = new File(info.sourceDir);
}
public ApplicationInfo getApplicationInfo() {
return mInfo;
}
public String getLabel() {
return mLabel;
}
public Drawable getIcon() {
if (mIcon == null) {
if (mApkFile.exists()) {
mIcon = mInfo.loadIcon(mLoader.mPm);
return mIcon;
} else {
mMounted = false;
}
} else if (!mMounted) {
// If the app wasn't mounted but is now mounted, reload
// its icon.
if (mApkFile.exists()) {
mMounted = true;
mIcon = mInfo.loadIcon(mLoader.mPm);
return mIcon;
}
} else {
return mIcon;
}
return mLoader.getContext().getResources().getDrawable(
android.R.drawable.sym_def_app_icon);
}
@Override public String toString() {
return mLabel;
}
void loadLabel(Context context) {
if (mLabel == null || !mMounted) {
if (!mApkFile.exists()) {
mMounted = false;
mLabel = mInfo.packageName;
} else {
mMounted = true;
CharSequence label = mInfo.loadLabel(context.getPackageManager());
mLabel = label != null ? label.toString() : mInfo.packageName;
}
}
}
}
public AppOpsCategory() {
}
public AppOpsCategory(int[] ops) {
Bundle args = new Bundle();
args.putIntArray("ops", ops);
setArguments(args);
}
/**
* This class holds the per-item data in our Loader.
*/
public static class AppOpEntry {
private final AppOpsManager.PackageOps mPkgOps;
private final AppOpsManager.OpEntry mOp;
private final AppEntry mApp;
public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app) {
mPkgOps = pkg;
mOp = op;
mApp = app;
}
public AppEntry getAppEntry() {
return mApp;
}
public AppOpsManager.PackageOps getPackageOps() {
return mPkgOps;
}
public AppOpsManager.OpEntry getOpEntry() {
return mOp;
}
public long getTime() {
return mOp.getTime();
}
@Override public String toString() {
return mApp.getLabel();
}
}
/**
* Perform alphabetical comparison of application entry objects.
*/
public static final Comparator<AppOpEntry> APP_OP_COMPARATOR = new Comparator<AppOpEntry>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppOpEntry object1, AppOpEntry object2) {
if (object1.getOpEntry().isRunning() != object2.getOpEntry().isRunning()) {
// Currently running ops go first.
return object1.getOpEntry().isRunning() ? -1 : 1;
}
if (object1.getTime() != object2.getTime()) {
// More recent times go first.
return object1.getTime() > object2.getTime() ? -1 : 1;
}
return sCollator.compare(object1.getAppEntry().getLabel(),
object2.getAppEntry().getLabel());
}
};
/**
* Helper for determining if the configuration has changed in an interesting
* way so we need to rebuild the app list.
*/
public static class InterestingConfigChanges {
final Configuration mLastConfiguration = new Configuration();
int mLastDensity;
boolean applyNewConfig(Resources res) {
int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE
|ActivityInfo.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) {
mLastDensity = res.getDisplayMetrics().densityDpi;
return true;
}
return false;
}
}
/**
* Helper class to look for interesting changes to the installed apps
* so that the loader can be updated.
*/
public static class PackageIntentReceiver extends BroadcastReceiver {
final AppListLoader mLoader;
public PackageIntentReceiver(AppListLoader loader) {
mLoader = loader;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mLoader.getContext().registerReceiver(this, sdFilter);
}
@Override public void onReceive(Context context, Intent intent) {
// Tell the loader about the change.
mLoader.onContentChanged();
}
}
/**
* A custom Loader that loads all of the installed applications.
*/
public static class AppListLoader extends AsyncTaskLoader<List<AppOpEntry>> {
final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
final AppOpsManager mAppOps;
final PackageManager mPm;
final int[] mOps;
final HashMap<String, AppEntry> mAppEntries = new HashMap<String, AppEntry>();
List<AppOpEntry> mApps;
PackageIntentReceiver mPackageObserver;
public AppListLoader(Context context, int[] ops) {
super(context);
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
mPm = context.getPackageManager();
mOps = ops;
}
@Override public List<AppOpEntry> loadInBackground() {
final Context context = getContext();
List<AppOpsManager.PackageOps> pkgs = mAppOps.getPackagesForOps(mOps);
List<AppOpEntry> entries = new ArrayList<AppOpEntry>(pkgs.size());
for (int i=0; i<pkgs.size(); i++) {
AppOpsManager.PackageOps pkgOps = pkgs.get(i);
AppEntry appEntry = mAppEntries.get(pkgOps.getPackageName());
if (appEntry == null) {
ApplicationInfo appInfo = null;
try {
appInfo = mPm.getApplicationInfo(pkgOps.getPackageName(),
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_UNINSTALLED_PACKAGES);
} catch (PackageManager.NameNotFoundException e) {
}
appEntry = new AppEntry(this, appInfo);
appEntry.loadLabel(context);
mAppEntries.put(pkgOps.getPackageName(), appEntry);
}
for (int j=0; j<pkgOps.getOps().size(); j++) {
AppOpsManager.OpEntry opEntry = pkgOps.getOps().get(j);
AppOpEntry entry = new AppOpEntry(pkgOps, opEntry, appEntry);
entries.add(entry);
}
}
// Sort the list.
Collections.sort(entries, APP_OP_COMPARATOR);
// Done!
return entries;
}
/**
* Called when there is new data to deliver to the client. The
* super class will take care of delivering it; the implementation
* here just adds a little more logic.
*/
@Override public void deliverResult(List<AppOpEntry> apps) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (apps != null) {
onReleaseResources(apps);
}
}
List<AppOpEntry> oldApps = apps;
mApps = apps;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(apps);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldApps != null) {
onReleaseResources(oldApps);
}
}
/**
* Handles a request to start the Loader.
*/
@Override protected void onStartLoading() {
if (mApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mApps);
}
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || mApps == null || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override public void onCanceled(List<AppOpEntry> apps) {
super.onCanceled(apps);
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(apps);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mApps != null) {
onReleaseResources(mApps);
mApps = null;
}
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
/**
* Helper function to take care of releasing resources associated
* with an actively loaded data set.
*/
protected void onReleaseResources(List<AppOpEntry> apps) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
public static class AppListAdapter extends ArrayAdapter<AppOpEntry> {
private final LayoutInflater mInflater;
private final CharSequence[] mOpNames;
private final CharSequence mRunningStr;
public AppListAdapter(Context context) {
super(context, android.R.layout.simple_list_item_2);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mOpNames = context.getResources().getTextArray(R.array.app_ops_names);
mRunningStr = context.getResources().getText(R.string.app_ops_running);
}
public void setData(List<AppOpEntry> data) {
clear();
if (data != null) {
addAll(data);
}
}
CharSequence opTimeToString(AppOpsManager.OpEntry op) {
if (op.isRunning()) {
return "Running";
}
return DateUtils.getRelativeTimeSpanString(op.getTime(),
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE);
}
/**
* Populate new items in the list.
*/
@Override public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.app_ops_item, parent, false);
} else {
view = convertView;
}
AppOpEntry item = getItem(position);
((ImageView)view.findViewById(R.id.app_icon)).setImageDrawable(
item.getAppEntry().getIcon());
((TextView)view.findViewById(R.id.app_name)).setText(item.getAppEntry().getLabel());
((TextView)view.findViewById(R.id.op_name)).setText(
mOpNames[item.getOpEntry().getOp()]);
((TextView)view.findViewById(R.id.op_time)).setText(opTimeToString(item.getOpEntry()));
return view;
}
}
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText("No applications");
// We have a menu item to show in action bar.
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
mAdapter = new AppListAdapter(getActivity());
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i("LoaderCustom", "Item clicked: " + id);
}
@Override public Loader<List<AppOpEntry>> onCreateLoader(int id, Bundle args) {
Bundle fargs = getArguments();
return new AppListLoader(getActivity(), fargs != null ? fargs.getIntArray("ops") : null);
}
@Override public void onLoadFinished(Loader<List<AppOpEntry>> loader, List<AppOpEntry> data) {
// Set the new data in the adapter.
mAdapter.setData(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
@Override public void onLoaderReset(Loader<List<AppOpEntry>> loader) {
// Clear the data in the adapter.
mAdapter.setData(null);
}
}

View File

@@ -0,0 +1,106 @@
package com.android.settings.applications;
import android.app.AppOpsManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.preference.PreferenceFrameLayout;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.settings.R;
public class AppOpsSummary extends Fragment {
// layout inflater object used to inflate views
private LayoutInflater mInflater;
private ViewGroup mContentContainer;
private View mRootView;
private ViewPager mViewPager;
CharSequence[] mPageNames;
static int[][] sPageOps = new int[][] {
// "Location" page.
new int[] { AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION,
AppOpsManager.OP_GPS},
// "Personal" page.
new int[] { AppOpsManager.OP_READ_CONTACTS, AppOpsManager.OP_WRITE_CONTACTS,
AppOpsManager.OP_READ_CALL_LOG, AppOpsManager.OP_WRITE_CALL_LOG },
// "Device" page.
new int[] { AppOpsManager.OP_VIBRATE },
};
int mCurPos;
class MyPagerAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return new AppOpsCategory(sPageOps[position]);
}
@Override
public int getCount() {
return sPageOps.length;
}
@Override
public CharSequence getPageTitle(int position) {
return mPageNames[position];
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurPos = position;
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
//updateCurrentTab(mCurPos);
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// initialize the inflater
mInflater = inflater;
View rootView = mInflater.inflate(R.layout.app_ops_summary,
container, false);
mContentContainer = container;
mRootView = rootView;
mPageNames = getResources().getTextArray(R.array.app_ops_categories);
mViewPager = (ViewPager) rootView.findViewById(R.id.pager);
MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager());
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(adapter);
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
// We have to do this now because PreferenceFrameLayout looks at it
// only when the view is added.
if (container instanceof PreferenceFrameLayout) {
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
}
return rootView;
}
}