Bug 953381 - Basic media casting control bar r=wesj

This commit is contained in:
Mark Finkle 2014-01-20 17:26:30 -05:00
Родитель f32c4e5d81
Коммит 8c92797a16
18 изменённых файлов: 217 добавлений и 1 удалений

Просмотреть файл

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 917896 requires a clobber due to bug 961339.
Bug 953381 requires a clobber due to bug 961339.

Просмотреть файл

@ -156,6 +156,7 @@ abstract public class BrowserApp extends GeckoApp
};
private FindInPageBar mFindInPageBar;
private MediaCastingBar mMediaCastingBar;
private boolean mAccessibilityEnabled = false;
@ -530,6 +531,7 @@ abstract public class BrowserApp extends GeckoApp
}
mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page);
mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
registerEventListener("CharEncoding:Data");
registerEventListener("CharEncoding:State");
@ -830,6 +832,11 @@ abstract public class BrowserApp extends GeckoApp
mFindInPageBar = null;
}
if (mMediaCastingBar != null) {
mMediaCastingBar.onDestroy();
mMediaCastingBar = null;
}
if (mSharedPreferencesHelper != null) {
mSharedPreferencesHelper.uninit();
mSharedPreferencesHelper = null;

Просмотреть файл

@ -0,0 +1,118 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONObject;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MediaCastingBar extends RelativeLayout implements View.OnClickListener, GeckoEventListener {
private static final String LOGTAG = "MediaCastingBar";
private TextView mCastingTo;
private ImageButton mMediaPlay;
private ImageButton mMediaPause;
private ImageButton mMediaStop;
private boolean mInflated = false;
public MediaCastingBar(Context context, AttributeSet attrs) {
super(context, attrs);
GeckoAppShell.getEventDispatcher().registerEventListener("Casting:Started", this);
GeckoAppShell.getEventDispatcher().registerEventListener("Casting:Stopped", this);
}
public void inflateContent() {
LayoutInflater inflater = LayoutInflater.from(getContext());
View content = inflater.inflate(R.layout.media_casting, this);
mMediaPlay = (ImageButton) content.findViewById(R.id.media_play);
mMediaPlay.setOnClickListener(this);
mMediaPause = (ImageButton) content.findViewById(R.id.media_pause);
mMediaPause.setOnClickListener(this);
mMediaStop = (ImageButton) content.findViewById(R.id.media_stop);
mMediaStop.setOnClickListener(this);
mCastingTo = (TextView) content.findViewById(R.id.media_casting_to);
// Capture clicks on the rest of the view to prevent them from
// leaking into other views positioned below.
content.setOnClickListener(this);
mInflated = true;
}
public void show() {
if (!mInflated)
inflateContent();
setVisibility(VISIBLE);
}
public void hide() {
setVisibility(GONE);
}
public void onDestroy() {
GeckoAppShell.getEventDispatcher().unregisterEventListener("Casting:Started", this);
GeckoAppShell.getEventDispatcher().unregisterEventListener("Casting:Stopped", this);
}
// View.OnClickListener implementation
@Override
public void onClick(View v) {
final int viewId = v.getId();
if (viewId == R.id.media_play) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Play", ""));
mMediaPlay.setVisibility(GONE);
mMediaPause.setVisibility(VISIBLE);
} else if (viewId == R.id.media_pause) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Pause", ""));
mMediaPause.setVisibility(GONE);
mMediaPlay.setVisibility(VISIBLE);
} else if (viewId == R.id.media_stop) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Stop", ""));
}
}
// GeckoEventListener implementation
@Override
public void handleMessage(final String event, final JSONObject message) {
final String device = message.optString("device");
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
if (event.equals("Casting:Started")) {
show();
if (!TextUtils.isEmpty(device)) {
mCastingTo.setText(device);
} else {
// Should not happen
mCastingTo.setText("");
Log.d(LOGTAG, "Device name is empty.");
}
mMediaPlay.setVisibility(GONE);
mMediaPause.setVisibility(VISIBLE);
} else if (event.equals("Casting:Stopped")) {
hide();
}
}
});
}
}

Просмотреть файл

@ -219,6 +219,13 @@ size. -->
<!ENTITY find_next "Next">
<!ENTITY find_close "Close">
<!-- Localization note (media_casting_to, media_play, media_pause, media_stop) : These strings are used
as alternate text for accessibility. They are not visible in the UI. -->
<!ENTITY media_casting_to "Casting to Device">
<!ENTITY media_play "Play">
<!ENTITY media_pause "Pause">
<!ENTITY media_stop "Stop">
<!ENTITY contextmenu_open_new_tab "Open in New Tab">
<!ENTITY contextmenu_open_private_tab "Open in Private Tab">
<!ENTITY contextmenu_open_in_reader "Open in Reader">

Просмотреть файл

@ -248,6 +248,7 @@ gbjar.sources += [
'LightweightTheme.java',
'LightweightThemeDrawable.java',
'LocaleManager.java',
'MediaCastingBar.java',
'MemoryMonitor.java',
'menu/GeckoMenu.java',
'menu/GeckoMenuInflater.java',

Двоичные данные
mobile/android/base/resources/drawable-hdpi/media_bar_pause.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 362 B

Двоичные данные
mobile/android/base/resources/drawable-hdpi/media_bar_play.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 670 B

Двоичные данные
mobile/android/base/resources/drawable-hdpi/media_bar_stop.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 763 B

Двоичные данные
mobile/android/base/resources/drawable-mdpi/media_bar_pause.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 252 B

Двоичные данные
mobile/android/base/resources/drawable-mdpi/media_bar_play.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 463 B

Двоичные данные
mobile/android/base/resources/drawable-mdpi/media_bar_stop.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 497 B

Двоичные данные
mobile/android/base/resources/drawable-xhdpi/media_bar_pause.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 389 B

Двоичные данные
mobile/android/base/resources/drawable-xhdpi/media_bar_play.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 853 B

Двоичные данные
mobile/android/base/resources/drawable-xhdpi/media_bar_stop.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -48,6 +48,13 @@
style="@style/FindBar"
android:visibility="gone"/>
<org.mozilla.gecko.MediaCastingBar android:id="@+id/media_casting"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
style="@style/FindBar"
android:visibility="gone"/>
<RelativeLayout android:id="@+id/camera_layout"
android:layout_height="wrap_content"
android:layout_width="wrap_content"

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout android:id="@+id/media_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<ImageButton android:id="@+id/media_play"
style="@style/FindBar.ImageButton"
android:contentDescription="@string/media_play"
android:src="@drawable/media_bar_play"
android:visibility="gone"/>
<ImageButton android:id="@+id/media_pause"
style="@style/FindBar.ImageButton"
android:contentDescription="@string/media_pause"
android:src="@drawable/media_bar_pause"/>
</RelativeLayout>
<TextView android:id="@+id/media_casting_to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/media_controls"
android:layout_centerVertical="true"
android:singleLine="true"
android:ellipsize="end"
android:textColor="#FFFFFFFF"
android:contentDescription="@string/media_casting_to"/>
<ImageButton android:id="@+id/media_stop"
style="@style/FindBar.ImageButton"
android:contentDescription="@string/media_stop"
android:layout_alignParentRight="true"
android:src="@drawable/media_bar_stop"/>
</merge>

Просмотреть файл

@ -83,6 +83,11 @@
<string name="find_next">&find_next;</string>
<string name="find_close">&find_close;</string>
<string name="media_casting_to">&media_casting_to;</string>
<string name="media_play">&media_play;</string>
<string name="media_pause">&media_pause;</string>
<string name="media_stop">&media_stop;</string>
<string name="settings">&settings;</string>
<string name="settings_title">&settings_title;</string>
<string name="pref_category_advanced">&pref_category_advanced;</string>

Просмотреть файл

@ -19,9 +19,17 @@ var CastingApps = {
this.filterCast,
this.openExternal.bind(this)
);
Services.obs.addObserver(this, "Casting:Play", false);
Services.obs.addObserver(this, "Casting:Pause", false);
Services.obs.addObserver(this, "Casting:Stop", false);
},
uninit: function ca_uninit() {
Services.obs.removeObserver(this, "Casting:Play");
Services.obs.removeObserver(this, "Casting:Pause");
Services.obs.removeObserver(this, "Casting:Stop");
NativeWindow.contextmenus.remove(this._castMenuId);
},
@ -29,6 +37,26 @@ var CastingApps = {
return Services.prefs.getBoolPref("browser.casting.enabled");
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "Casting:Play":
if (this.session && this.session.remoteMedia.status == "paused") {
this.session.remoteMedia.play();
}
break;
case "Casting:Pause":
if (this.session && this.session.remoteMedia.status == "started") {
this.session.remoteMedia.pause();
}
break;
case "Casting:Stop":
if (this.session) {
this.closeExternal();
}
break;
}
},
makeURI: function makeURI(aURL, aOriginCharset, aBaseURI) {
return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
},
@ -192,9 +220,11 @@ var CastingApps = {
}
aRemoteMedia.load(this.session.data);
sendMessageToJava({ type: "Casting:Started", device: this.session.service.friendlyName });
},
onRemoteMediaStop: function(aRemoteMedia) {
sendMessageToJava({ type: "Casting:Stopped" });
},
onRemoteMediaStatus: function(aRemoteMedia) {