Merge "Fix issue #6636731: Mariner animation ring gets stuck" into jb-dev
diff --git a/api/current.txt b/api/current.txt
index e4b098f..cd71bfd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11566,6 +11566,8 @@
method public java.lang.CharSequence getName(android.content.Context);
method public java.lang.CharSequence getStatus();
method public int getSupportedTypes();
+ method public java.lang.Object getTag();
+ method public void setTag(java.lang.Object);
}
public static class MediaRouter.SimpleCallback extends android.media.MediaRouter.Callback {
@@ -11580,14 +11582,12 @@
}
public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
- method public java.lang.Object getTag();
method public void setIconDrawable(android.graphics.drawable.Drawable);
method public void setIconResource(int);
method public void setName(java.lang.CharSequence);
method public void setName(int);
method public void setRemoteControlClient(android.media.RemoteControlClient);
method public void setStatus(java.lang.CharSequence);
- method public void setTag(java.lang.Object);
}
public class MediaScannerConnection implements android.content.ServiceConnection {
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 0bc7371..96a6438 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -53,11 +53,7 @@
unlink(pkgdir);
return -errno;
}
- if (chown(pkgdir, uid, gid) < 0) {
- ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
- }
+
if (mkdir(libdir, 0755) < 0) {
ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
unlink(pkgdir);
@@ -75,6 +71,13 @@
unlink(pkgdir);
return -errno;
}
+
+ if (chown(pkgdir, uid, gid) < 0) {
+ ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(libdir);
+ unlink(pkgdir);
+ return -errno;
+ }
return 0;
}
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
index 6c9a047..e1a48be 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
@@ -36,6 +36,8 @@
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.Checkable;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
@@ -44,6 +46,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
/**
* This class implements the route chooser dialog for {@link MediaRouter}.
@@ -58,11 +61,7 @@
private static final int[] ITEM_LAYOUTS = new int[] {
R.layout.media_route_list_item_top_header,
R.layout.media_route_list_item_section_header,
- R.layout.media_route_list_item
- };
-
- private static final int[] GROUP_ITEM_LAYOUTS = new int[] {
- R.layout.media_route_list_item_top_header,
+ R.layout.media_route_list_item,
R.layout.media_route_list_item_checkable,
R.layout.media_route_list_item_collapse_group
};
@@ -74,7 +73,6 @@
private LauncherListener mLauncherListener;
private View.OnClickListener mExtendedSettingsListener;
private RouteAdapter mAdapter;
- private GroupAdapter mGroupAdapter;
private ListView mListView;
final RouteComparator mComparator = new RouteComparator();
@@ -99,10 +97,6 @@
if (mLauncherListener != null) {
mLauncherListener.onDetached(this);
}
- if (mGroupAdapter != null) {
- mRouter.removeCallback(mGroupAdapter.mCallback);
- mGroupAdapter = null;
- }
if (mAdapter != null) {
mRouter.removeCallback(mAdapter.mCallback);
mAdapter = null;
@@ -139,45 +133,18 @@
}
final ListView list = (ListView) layout.findViewById(R.id.list);
- list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setItemsCanFocus(true);
list.setAdapter(mAdapter = new RouteAdapter());
- list.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
list.setOnItemClickListener(mAdapter);
mListView = list;
mRouter.addCallback(mRouteTypes, mAdapter.mCallback);
+ mAdapter.scrollToSelectedItem();
+
return layout;
}
- void onExpandGroup(RouteGroup info) {
- mGroupAdapter = new GroupAdapter(info);
- mRouter.addCallback(mRouteTypes, mGroupAdapter.mCallback);
- mListView.setAdapter(mGroupAdapter);
- mListView.setOnItemClickListener(mGroupAdapter);
- mListView.setItemsCanFocus(false);
- mListView.clearChoices();
- mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- mGroupAdapter.initCheckedItems();
-
- getDialog().setCanceledOnTouchOutside(false);
- }
-
- void onDoneGrouping() {
- mListView.setAdapter(mAdapter);
- mListView.setOnItemClickListener(mAdapter);
- mListView.setItemsCanFocus(true);
- mListView.clearChoices();
- mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- mListView.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
-
- mRouter.removeCallback(mGroupAdapter.mCallback);
- mGroupAdapter = null;
-
- getDialog().setCanceledOnTouchOutside(true);
- }
-
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new RouteChooserDialog(getActivity(), getTheme());
@@ -186,14 +153,6 @@
@Override
public void onResume() {
super.onResume();
-
- if (mListView != null) {
- if (mGroupAdapter != null) {
- mGroupAdapter.initCheckedItems();
- } else {
- mListView.setItemChecked(mAdapter.getSelectedRoutePosition(), true);
- }
- }
}
private static class ViewHolder {
@@ -203,52 +162,139 @@
public ImageButton expandGroupButton;
public RouteAdapter.ExpandGroupListener expandGroupListener;
public int position;
+ public CheckBox check;
}
private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener {
private static final int VIEW_TOP_HEADER = 0;
private static final int VIEW_SECTION_HEADER = 1;
private static final int VIEW_ROUTE = 2;
+ private static final int VIEW_GROUPING_ROUTE = 3;
+ private static final int VIEW_GROUPING_DONE = 4;
- private int mSelectedItemPosition;
+ private int mSelectedItemPosition = -1;
private final ArrayList<Object> mItems = new ArrayList<Object>();
final MediaRouterCallback mCallback = new MediaRouterCallback();
+ private RouteCategory mCategoryEditingGroups;
+ private RouteGroup mEditingGroup;
+
+ // Temporary lists for manipulation
+ private final ArrayList<RouteInfo> mCatRouteList = new ArrayList<RouteInfo>();
+ private final ArrayList<RouteInfo> mSortRouteList = new ArrayList<RouteInfo>();
+
+ private boolean mIgnoreUpdates;
+
RouteAdapter() {
update();
}
void update() {
- // TODO this is kind of naive, but our data sets are going to be
- // fairly small on average.
+ /*
+ * This is kind of wacky, but our data sets are going to be
+ * fairly small on average. Ideally we should be able to do some of this stuff
+ * in-place instead.
+ *
+ * Basic idea: each entry in mItems represents an item in the list for quick access.
+ * Entries can be a RouteCategory (section header), a RouteInfo with a category of
+ * mCategoryEditingGroups (a flattened RouteInfo pulled out of its group, allowing
+ * the user to change the group),
+ */
+ if (mIgnoreUpdates) return;
+
mItems.clear();
final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
+ mSelectedItemPosition = -1;
- final ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
+ List<RouteInfo> routes;
final int catCount = mRouter.getCategoryCount();
for (int i = 0; i < catCount; i++) {
final RouteCategory cat = mRouter.getCategoryAt(i);
- cat.getRoutes(routes);
+ routes = cat.getRoutes(mCatRouteList);
mItems.add(cat);
- final int routeCount = routes.size();
- for (int j = 0; j < routeCount; j++) {
- final RouteInfo info = routes.get(j);
- if (info == selectedRoute) {
- mSelectedItemPosition = mItems.size();
- }
- mItems.add(info);
+ if (cat == mCategoryEditingGroups) {
+ addGroupEditingCategoryRoutes(routes);
+ } else {
+ addSelectableRoutes(selectedRoute, routes);
}
+
+ routes.clear();
}
notifyDataSetChanged();
- if (mListView != null) {
+ if (mListView != null && mSelectedItemPosition >= 0) {
mListView.setItemChecked(mSelectedItemPosition, true);
}
}
+ void scrollToEditingGroup() {
+ if (mCategoryEditingGroups == null || mListView == null) return;
+
+ int pos = 0;
+ int bound = 0;
+ final int itemCount = mItems.size();
+ for (int i = 0; i < itemCount; i++) {
+ final Object item = mItems.get(i);
+ if (item != null && item == mCategoryEditingGroups) {
+ bound = i;
+ }
+ if (item == null) {
+ pos = i;
+ break; // this is always below the category header; we can stop here.
+ }
+ }
+
+ mListView.smoothScrollToPosition(pos, bound);
+ }
+
+ void scrollToSelectedItem() {
+ if (mListView == null || mSelectedItemPosition < 0) return;
+
+ mListView.smoothScrollToPosition(mSelectedItemPosition);
+ }
+
+ void addSelectableRoutes(RouteInfo selectedRoute, List<RouteInfo> from) {
+ final int routeCount = from.size();
+ for (int j = 0; j < routeCount; j++) {
+ final RouteInfo info = from.get(j);
+ if (info == selectedRoute) {
+ mSelectedItemPosition = mItems.size();
+ }
+ mItems.add(info);
+ }
+ }
+
+ void addGroupEditingCategoryRoutes(List<RouteInfo> from) {
+ // Unpack groups and flatten for presentation
+ // mSortRouteList will always be empty here.
+ final int topCount = from.size();
+ for (int i = 0; i < topCount; i++) {
+ final RouteInfo route = from.get(i);
+ final RouteGroup group = route.getGroup();
+ if (group == route) {
+ // This is a group, unpack it.
+ final int groupCount = group.getRouteCount();
+ for (int j = 0; j < groupCount; j++) {
+ final RouteInfo innerRoute = group.getRouteAt(j);
+ mSortRouteList.add(innerRoute);
+ }
+ } else {
+ mSortRouteList.add(route);
+ }
+ }
+ // Sort by name. This will keep the route positions relatively stable even though they
+ // will be repeatedly added and removed.
+ Collections.sort(mSortRouteList, mComparator);
+
+ mItems.addAll(mSortRouteList);
+ mSortRouteList.clear();
+
+ mItems.add(null); // Sentinel reserving space for the "done" button.
+ }
+
@Override
public int getCount() {
return mItems.size();
@@ -256,7 +302,7 @@
@Override
public int getViewTypeCount() {
- return 3;
+ return 5;
}
@Override
@@ -264,7 +310,13 @@
final Object item = getItem(position);
if (item instanceof RouteCategory) {
return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER;
+ } else if (item == null) {
+ return VIEW_GROUPING_DONE;
} else {
+ final RouteInfo info = (RouteInfo) item;
+ if (info.getCategory() == mCategoryEditingGroups) {
+ return VIEW_GROUPING_ROUTE;
+ }
return VIEW_ROUTE;
}
}
@@ -276,7 +328,14 @@
@Override
public boolean isEnabled(int position) {
- return getItemViewType(position) == VIEW_ROUTE;
+ switch (getItemViewType(position)) {
+ case VIEW_ROUTE:
+ case VIEW_GROUPING_ROUTE:
+ case VIEW_GROUPING_DONE:
+ return true;
+ default:
+ return false;
+ }
}
@Override
@@ -301,6 +360,7 @@
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
+ holder.check = (CheckBox) convertView.findViewById(R.id.check);
holder.expandGroupButton = (ImageButton) convertView.findViewById(
R.id.expand_button);
if (holder.expandGroupButton != null) {
@@ -322,12 +382,19 @@
holder.position = position;
}
- if (viewType == VIEW_ROUTE) {
- bindItemView(position, holder);
- } else {
- bindHeaderView(position, holder);
+ switch (viewType) {
+ case VIEW_ROUTE:
+ case VIEW_GROUPING_ROUTE:
+ bindItemView(position, holder);
+ break;
+ case VIEW_SECTION_HEADER:
+ case VIEW_TOP_HEADER:
+ bindHeaderView(position, holder);
+ break;
}
+ convertView.setActivated(position == mSelectedItemPosition);
+
return convertView;
}
@@ -351,14 +418,24 @@
RouteCategory cat = info.getCategory();
boolean canGroup = false;
- if (cat.isGroupable()) {
- final RouteGroup group = (RouteGroup) info;
- canGroup = group.getRouteCount() > 1 ||
- getItemViewType(position - 1) == VIEW_ROUTE ||
- (position < getCount() - 1 && getItemViewType(position + 1) == VIEW_ROUTE);
+ if (cat == mCategoryEditingGroups) {
+ RouteGroup group = info.getGroup();
+ holder.check.setEnabled(group.getRouteCount() > 1);
+ holder.check.setChecked(group == mEditingGroup);
+ } else {
+ if (cat.isGroupable()) {
+ final RouteGroup group = (RouteGroup) info;
+ canGroup = group.getRouteCount() > 1 ||
+ getItemViewType(position - 1) == VIEW_ROUTE ||
+ (position < getCount() - 1 &&
+ getItemViewType(position + 1) == VIEW_ROUTE);
+ }
}
- holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
- holder.expandGroupListener.position = position;
+
+ if (holder.expandGroupButton != null) {
+ holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
+ holder.expandGroupListener.position = position;
+ }
}
void bindHeaderView(int position, ViewHolder holder) {
@@ -372,14 +449,62 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- ListView lv = (ListView) parent;
- final Object item = getItem(lv.getCheckedItemPosition());
- if (!(item instanceof RouteInfo)) {
- // Oops. Stale event running around? Skip it.
+ final int type = getItemViewType(position);
+ if (type == VIEW_SECTION_HEADER || type == VIEW_TOP_HEADER) {
return;
+ } else if (type == VIEW_GROUPING_DONE) {
+ finishGrouping();
+ return;
+ } else {
+ final Object item = getItem(position);
+ if (!(item instanceof RouteInfo)) {
+ // Oops. Stale event running around? Skip it.
+ return;
+ }
+
+ final RouteInfo route = (RouteInfo) item;
+ if (type == VIEW_ROUTE) {
+ mRouter.selectRouteInt(mRouteTypes, route);
+ dismiss();
+ } else if (type == VIEW_GROUPING_ROUTE) {
+ final Checkable c = (Checkable) view;
+ final boolean wasChecked = c.isChecked();
+
+ mIgnoreUpdates = true;
+ RouteGroup oldGroup = route.getGroup();
+ if (!wasChecked && oldGroup != mEditingGroup) {
+ // Assumption: in a groupable category oldGroup will never be null.
+ if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
+ // Old group was selected but is now empty. Select the group
+ // we're manipulating since that's where the last route went.
+ mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
+ }
+ oldGroup.removeRoute(route);
+ mEditingGroup.addRoute(route);
+ c.setChecked(true);
+ } else if (wasChecked && mEditingGroup.getRouteCount() > 1) {
+ mEditingGroup.removeRoute(route);
+
+ // In a groupable category this will add
+ // the route into its own new group.
+ mRouter.addRouteInt(route);
+ }
+ mIgnoreUpdates = false;
+ update();
+ }
}
- mRouter.selectRouteInt(mRouteTypes, (RouteInfo) item);
- dismiss();
+ }
+
+ boolean isGrouping() {
+ return mCategoryEditingGroups != null;
+ }
+
+ void finishGrouping() {
+ mCategoryEditingGroups = null;
+ mEditingGroup = null;
+ getDialog().setCanceledOnTouchOutside(true);
+ update();
+ scrollToSelectedItem();
}
class ExpandGroupListener implements View.OnClickListener {
@@ -389,7 +514,13 @@
public void onClick(View v) {
// Assumption: this is only available for the user to click if we're presenting
// a groupable category, where every top-level route in the category is a group.
- onExpandGroup((RouteGroup) getItem(position));
+ final RouteGroup group = (RouteGroup) getItem(position);
+ mEditingGroup = group;
+ mCategoryEditingGroups = group.getCategory();
+ getDialog().setCanceledOnTouchOutside(false);
+ mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
+ update();
+ scrollToEditingGroup();
}
}
@@ -411,6 +542,9 @@
@Override
public void onRouteRemoved(MediaRouter router, RouteInfo info) {
+ if (info == mEditingGroup) {
+ finishGrouping();
+ }
update();
}
@@ -432,246 +566,6 @@
}
}
- private class GroupAdapter extends BaseAdapter implements ListView.OnItemClickListener {
- private static final int VIEW_HEADER = 0;
- private static final int VIEW_ROUTE = 1;
- private static final int VIEW_DONE = 2;
-
- private RouteGroup mPrimary;
- private RouteCategory mCategory;
- private final ArrayList<RouteInfo> mTempList = new ArrayList<RouteInfo>();
- private final ArrayList<RouteInfo> mFlatRoutes = new ArrayList<RouteInfo>();
- private boolean mIgnoreUpdates;
-
- final MediaRouterCallback mCallback = new MediaRouterCallback();
-
- public GroupAdapter(RouteGroup primary) {
- mPrimary = primary;
- mCategory = primary.getCategory();
- update();
- }
-
- @Override
- public int getCount() {
- return mFlatRoutes.size() + 2;
- }
-
- @Override
- public int getViewTypeCount() {
- return 3;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position == 0) {
- return VIEW_HEADER;
- } else if (position == getCount() - 1) {
- return VIEW_DONE;
- }
- return VIEW_ROUTE;
- }
-
- void update() {
- if (mIgnoreUpdates) return;
- mFlatRoutes.clear();
- mCategory.getRoutes(mTempList);
-
- // Unpack groups and flatten for presentation
- final int topCount = mTempList.size();
- for (int i = 0; i < topCount; i++) {
- final RouteInfo route = mTempList.get(i);
- final RouteGroup group = route.getGroup();
- if (group == route) {
- // This is a group, unpack it.
- final int groupCount = group.getRouteCount();
- for (int j = 0; j < groupCount; j++) {
- final RouteInfo innerRoute = group.getRouteAt(j);
- mFlatRoutes.add(innerRoute);
- }
- } else {
- mFlatRoutes.add(route);
- }
- }
- mTempList.clear();
-
- // Sort by name. This will keep the route positions relatively stable even though they
- // will be repeatedly added and removed.
- Collections.sort(mFlatRoutes, mComparator);
- notifyDataSetChanged();
- }
-
- void initCheckedItems() {
- if (mIgnoreUpdates) return;
- mListView.clearChoices();
- int count = mFlatRoutes.size();
- for (int i = 0; i < count; i++){
- final RouteInfo route = mFlatRoutes.get(i);
- if (route.getGroup() == mPrimary) {
- mListView.setItemChecked(i + 1, true);
- }
- }
- }
-
- @Override
- public Object getItem(int position) {
- if (position == 0) {
- return mCategory;
- } else if (position == getCount() - 1) {
- return null; // Done
- }
- return mFlatRoutes.get(position - 1);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return false;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return position > 0;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final int viewType = getItemViewType(position);
-
- ViewHolder holder;
- if (convertView == null) {
- convertView = mInflater.inflate(GROUP_ITEM_LAYOUTS[viewType], parent, false);
- holder = new ViewHolder();
- holder.position = position;
- holder.text1 = (TextView) convertView.findViewById(R.id.text1);
- holder.text2 = (TextView) convertView.findViewById(R.id.text2);
- holder.icon = (ImageView) convertView.findViewById(R.id.icon);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- holder.position = position;
- }
-
- if (viewType == VIEW_ROUTE) {
- bindItemView(position, holder);
- } else if (viewType == VIEW_HEADER) {
- bindHeaderView(position, holder);
- }
-
- return convertView;
- }
-
- void bindItemView(int position, ViewHolder holder) {
- RouteInfo info = (RouteInfo) getItem(position);
- holder.text1.setText(info.getName(getActivity()));
- final CharSequence status = info.getStatus();
- if (TextUtils.isEmpty(status)) {
- holder.text2.setVisibility(View.GONE);
- } else {
- holder.text2.setVisibility(View.VISIBLE);
- holder.text2.setText(status);
- }
- }
-
- void bindHeaderView(int position, ViewHolder holder) {
- holder.text1.setText(mCategory.getName(getActivity()));
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (getItemViewType(position) == VIEW_DONE) {
- onDoneGrouping();
- return;
- }
-
- final ListView lv = (ListView) parent;
- final RouteInfo route = mFlatRoutes.get(position - 1);
- final boolean checked = lv.isItemChecked(position);
-
- mIgnoreUpdates = true;
- RouteGroup oldGroup = route.getGroup();
- if (checked && oldGroup != mPrimary) {
- // Assumption: in a groupable category oldGroup will never be null.
- oldGroup.removeRoute(route);
-
- // If the group is now empty, remove the group too.
- if (oldGroup.getRouteCount() == 0) {
- if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
- // Old group was selected but is now empty. Select the group
- // we're manipulating since that's where the last route went.
- mRouter.selectRouteInt(mRouteTypes, mPrimary);
- }
- mRouter.removeRouteInt(oldGroup);
- }
-
- mPrimary.addRoute(route);
- } else if (!checked) {
- if (mPrimary.getRouteCount() > 1) {
- mPrimary.removeRoute(route);
-
- // In a groupable category this will add the route into its own new group.
- mRouter.addRouteInt(route);
- } else {
- // We're about to remove the last route.
- // Don't let this happen, as it would be silly.
- // Turn the checkmark back on again. Silly user!
- lv.setItemChecked(position, true);
- }
- }
- mIgnoreUpdates = false;
- update();
- initCheckedItems();
- }
-
- class MediaRouterCallback extends MediaRouter.Callback {
- @Override
- public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
- }
-
- @Override
- public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
- }
-
- @Override
- public void onRouteAdded(MediaRouter router, RouteInfo info) {
- update();
- initCheckedItems();
- }
-
- @Override
- public void onRouteRemoved(MediaRouter router, RouteInfo info) {
- if (info == mPrimary) {
- // Can't keep grouping, clean it up.
- onDoneGrouping();
- } else {
- update();
- initCheckedItems();
- }
- }
-
- @Override
- public void onRouteChanged(MediaRouter router, RouteInfo info) {
- update();
- }
-
- @Override
- public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
- int index) {
- update();
- initCheckedItems();
- }
-
- @Override
- public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
- update();
- initCheckedItems();
- }
- }
- }
-
class RouteComparator implements Comparator<RouteInfo> {
@Override
public int compare(RouteInfo lhs, RouteInfo rhs) {
@@ -687,8 +581,8 @@
@Override
public void onBackPressed() {
- if (mGroupAdapter != null) {
- onDoneGrouping();
+ if (mAdapter != null && mAdapter.isGrouping()) {
+ mAdapter.finishGrouping();
} else {
super.onBackPressed();
}
diff --git a/core/res/res/layout/media_route_list_item_checkable.xml b/core/res/res/layout/media_route_list_item_checkable.xml
index f6ba09e..d0bffb6 100644
--- a/core/res/res/layout/media_route_list_item_checkable.xml
+++ b/core/res/res/layout/media_route_list_item_checkable.xml
@@ -17,6 +17,7 @@
<com.android.internal.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
+ android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical">
<ImageView android:layout_width="56dp"
diff --git a/core/res/res/layout/media_route_list_item_collapse_group.xml b/core/res/res/layout/media_route_list_item_collapse_group.xml
index 3f4b1c0..d605c18 100644
--- a/core/res/res/layout/media_route_list_item_collapse_group.xml
+++ b/core/res/res/layout/media_route_list_item_collapse_group.xml
@@ -14,26 +14,31 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeightSmall"
- android:background="#19ffffff"
- android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
- android:paddingRight="?android:attr/listPreferredItemPaddingRight"
- android:gravity="center_vertical">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:background="#19ffffff"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/listPreferredItemPaddingRight"
+ android:gravity="center_vertical">
- <TextView android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:text="@string/media_route_chooser_grouping_done"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+ <TextView android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:text="@string/media_route_chooser_grouping_done"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_media_group_collapse"
- android:scaleType="center" />
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_media_group_collapse"
+ android:scaleType="center" />
-</LinearLayout>
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/data/sounds/ringtones/ogg/Themos.ogg b/data/sounds/ringtones/ogg/Themos.ogg
index bc850b8..4ddc71c 100644
--- a/data/sounds/ringtones/ogg/Themos.ogg
+++ b/data/sounds/ringtones/ogg/Themos.ogg
Binary files differ
diff --git a/data/sounds/ringtones/wav/Themos.wav b/data/sounds/ringtones/wav/Themos.wav
index d4d5c6e..fa3178f 100644
--- a/data/sounds/ringtones/wav/Themos.wav
+++ b/data/sounds/ringtones/wav/Themos.wav
Binary files differ
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index b497f63..9e70b7f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -271,9 +271,9 @@
if (cat.isGroupable() && !(info instanceof RouteGroup)) {
// Enforce that any added route in a groupable category must be in a group.
final RouteGroup group = new RouteGroup(info.getCategory());
- group.addRoute(info);
sStatic.mRoutes.add(group);
dispatchRouteAdded(group);
+ group.addRoute(info);
info = group;
} else {
@@ -552,6 +552,8 @@
final RouteCategory mCategory;
Drawable mIcon;
+ private Object mTag;
+
RouteInfo(RouteCategory category) {
mCategory = category;
}
@@ -621,6 +623,29 @@
return mIcon;
}
+ /**
+ * Set an application-specific tag object for this route.
+ * The application may use this to store arbitrary data associated with the
+ * route for internal tracking.
+ *
+ * <p>Note that the lifespan of a route may be well past the lifespan of
+ * an Activity or other Context; take care that objects you store here
+ * will not keep more data in memory alive than you intend.</p>
+ *
+ * @param tag Arbitrary, app-specific data for this route to hold for later use
+ */
+ public void setTag(Object tag) {
+ mTag = tag;
+ }
+
+ /**
+ * @return The tag object previously set by the application
+ * @see #setTag(Object)
+ */
+ public Object getTag() {
+ return mTag;
+ }
+
void setStatusInt(CharSequence status) {
if (!status.equals(mStatus)) {
mStatus = status;
@@ -652,7 +677,6 @@
*/
public static class UserRouteInfo extends RouteInfo {
RemoteControlClient mRcc;
- private Object mTag;
UserRouteInfo(RouteCategory category) {
super(category);
@@ -720,29 +744,6 @@
public void setIconResource(int resId) {
setIconDrawable(sStatic.mResources.getDrawable(resId));
}
-
- /**
- * Set an application-specific tag object for this route.
- * The application may use this to store arbitrary data associated with the
- * route for internal tracking.
- *
- * <p>Note that the lifespan of a route may be well past the lifespan of
- * an Activity or other Context; take care that objects you store here
- * will not keep more data in memory alive than you intend.</p>
- *
- * @param tag Arbitrary, app-specific data for this route to hold for later use
- */
- public void setTag(Object tag) {
- mTag = tag;
- }
-
- /**
- * @return The tag object previously set by the application
- * @see #setTag(Object)
- */
- public Object getTag() {
- return mTag;
- }
}
/**
@@ -888,6 +889,12 @@
void routeUpdated() {
int types = 0;
final int count = mRoutes.size();
+ if (count == 0) {
+ // Don't keep empty groups in the router.
+ MediaRouter.removeRoute(this);
+ return;
+ }
+
for (int i = 0; i < count; i++) {
types |= mRoutes.get(i).mSupportedTypes;
}
@@ -901,6 +908,7 @@
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
final RouteInfo info = mRoutes.get(i);
+ // TODO: There's probably a much more correct way to localize this.
if (i > 0) sb.append(", ");
sb.append(info.mName);
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1eb353f..f18e33e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -117,7 +117,7 @@
</string>
<!-- Separator for PLMN and SPN in network name. -->
- <string name="status_bar_network_name_separator" translatable="false">"\n"</string>
+ <string name="status_bar_network_name_separator" translatable="false">|</string>
<!-- Network connection string for Bluetooth Reverse Tethering -->
<string name="bluetooth_tethered">Bluetooth tethered</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9c99653..3c19ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -462,11 +462,12 @@
signalCluster.setNetworkController(mNetworkController);
if (SHOW_CARRIER_LABEL) {
- // for wifi-only devices, we show SSID; otherwise, we show PLMN
+ // for mobile devices, we always show mobile connection info here (SPN/PLMN)
+ // for other devices, we show whatever network is connected
if (mNetworkController.hasMobileDataFeature()) {
mNetworkController.addMobileLabelView(mCarrierLabel);
} else {
- mNetworkController.addWifiLabelView(mCarrierLabel);
+ mNetworkController.addCombinedLabelView(mCarrierLabel);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index b8f6054..1068267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -121,8 +121,12 @@
private int mWimaxSignal = 0;
private int mWimaxState = 0;
private int mWimaxExtraState = 0;
+
// data connectivity (regardless of state, can we access the internet?)
// state of inet connection - 0 not connected, 100 connected
+ private boolean mConnected = false;
+ private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+ private String mConnectedNetworkTypeName;
private int mInetCondition = 0;
private static final int INET_CONDITION_THRESHOLD = 50;
@@ -868,6 +872,16 @@
.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo info = connManager.getActiveNetworkInfo();
+ // Are we connected at all, by any interface?
+ mConnected = info != null && info.isConnected();
+ if (mConnected) {
+ mConnectedNetworkType = info.getType();
+ mConnectedNetworkTypeName = info.getTypeName();
+ } else {
+ mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+ mConnectedNetworkTypeName = null;
+ }
+
int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
if (CHATTY) {
@@ -912,12 +926,13 @@
// - We are connected to mobile data, or
// - We are not connected to mobile data, as long as the *reason* packets are not
// being routed over that link is that we have better connectivity via wifi.
- // If data is disconnected for some other reason but wifi is connected, we show nothing.
+ // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
+ // is connected, we show nothing.
// Otherwise (nothing connected) we show "No internet connection".
if (mDataConnected) {
mobileLabel = mNetworkName;
- } else if (mWifiConnected) {
+ } else if (mConnected) {
if (hasService()) {
mobileLabel = mNetworkName;
} else {
@@ -997,6 +1012,12 @@
R.string.accessibility_bluetooth_tether);
}
+ final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
+ if (ethernetConnected) {
+ // TODO: icons and strings for Ethernet connectivity
+ combinedLabel = mConnectedNetworkTypeName;
+ }
+
if (mAirplaneMode &&
(mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
// Only display the flight-mode icon if not in "emergency calls only" mode.
@@ -1023,7 +1044,7 @@
combinedSignalIconId = mDataSignalIconId;
}
}
- else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
+ else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
// pretty much totally disconnected
combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
@@ -1224,6 +1245,9 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NetworkController state:");
+ pw.println(String.format(" %s network type %d (%s)",
+ mConnected?"CONNECTED":"DISCONNECTED",
+ mConnectedNetworkType, mConnectedNetworkTypeName));
pw.println(" - telephony ------");
pw.print(" hasService()=");
pw.println(hasService());