Implemented a scalable control pad (remote) (#428)

* Refactored RemoteFragment and created a compound view for the
     actual remote. I called it ControlPad to make it more clear what
     its main function is.
   * Implemented a custom grid layout (SquareGridLayout) that will
     always be square. When its width and height are both set to
     match_parent, it will take the smallest of the two as the
     actual size.
   * For devices with a smallest width smaller then 360dp the ControlPad
     is sized to the maximum available space. For larger devices we still
     use the old fixed sizes.
This commit is contained in:
Martijn Brekhof 2017-08-30 20:53:47 +02:00 committed by Synced Synapse
parent 2761c8651b
commit 3106a5fd61
13 changed files with 1287 additions and 591 deletions

View File

@ -115,6 +115,7 @@ dependencies {
compile "com.android.support:cardview-v7:${supportLibVersion}"
compile "com.android.support:preference-v14:${supportLibVersion}"
compile "com.android.support:support-v13:${supportLibVersion}"
compile "com.android.support:gridlayout-v7:${supportLibVersion}"
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.2'
compile 'com.jakewharton:butterknife:6.1.0'

View File

@ -15,24 +15,14 @@
*/
package org.xbmc.kore.ui.sections.remote;
import android.annotation.TargetApi;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.BitmapFactory;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -56,8 +46,8 @@ import org.xbmc.kore.jsonrpc.method.Player;
import org.xbmc.kore.jsonrpc.type.GlobalType;
import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.PlayerType;
import org.xbmc.kore.ui.widgets.ControlPad;
import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.RepeatListener;
import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils;
@ -74,7 +64,8 @@ import butterknife.Optional;
* Remote view
*/
public class RemoteFragment extends Fragment
implements HostConnectionObserver.PlayerEventsObserver {
implements HostConnectionObserver.PlayerEventsObserver,
ControlPad.OnPadButtonsListener {
private static final String TAG = LogUtils.makeLogTag(RemoteFragment.class);
/**
@ -102,9 +93,35 @@ public class RemoteFragment extends Fragment
*/
private String currentNowPlayingItemType = null;
private final Packet leftButtonPacket =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_LEFT, false, true,
true, (short)0, (byte)0);
private final Packet rightButtonPacket =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_RIGHT, false, true,
true, (short)0, (byte)0);
private final Packet upButtonPacket =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_UP, false, true,
true, (short)0, (byte)0);
private final Packet downButtonPacket =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_DOWN, false, true,
true, (short)0, (byte)0);
private final Packet selectButtonPack =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, ButtonCodes.REMOTE_SELECT, false, true,
true, (short)0, (byte)0);
private final ApiMethod<String> downButtonAction = new Input.Down();
private final ApiMethod<String> leftButtonAction = new Input.Left();
private final ApiMethod<String> upButtonAction = new Input.Up();
private final ApiMethod<String> rightButtonAction = new Input.Right();
private final ApiMethod<String> selectButtonAction = new Input.Select();
private final ApiMethod<String> backButtonAction = new Input.Back();
private final ApiMethod<String> infoButtonAction = new Input.ExecuteAction(Input.ExecuteAction.INFO);
private final ApiMethod<String> contextButtonAction = new Input.ExecuteAction(Input.ExecuteAction.CONTEXTMENU);
private final ApiMethod<String> osdButtonAction = new Input.ExecuteAction(Input.ExecuteAction.OSD);
@InjectView(R.id.info_panel) RelativeLayout infoPanel;
@InjectView(R.id.media_panel) RelativeLayout mediaPanel;
@InjectView(R.id.remote) RelativeLayout remotePanel;
@InjectView(R.id.remote) ControlPad controlPad;
@InjectView(R.id.info_title) TextView infoTitle;
@InjectView(R.id.info_message) TextView infoMessage;
@ -126,16 +143,6 @@ public class RemoteFragment extends Fragment
@Optional @InjectView(R.id.weather) ImageButton weatherButton;
@Optional @InjectView(R.id.system) ImageButton systemButton;
@InjectView(R.id.select) ImageView selectButton;
@InjectView(R.id.left) ImageView leftButton;
@InjectView(R.id.right) ImageView rightButton;
@InjectView(R.id.up) ImageView upButton;
@InjectView(R.id.down) ImageView downButton;
@InjectView(R.id.back) ImageView backButton;
@InjectView(R.id.info) ImageView infoButton;
@InjectView(R.id.context) ImageView contextButton;
@InjectView(R.id.osd) ImageView osdButton;
@InjectView(R.id.art) ImageView thumbnail;
@InjectView(R.id.title) TextView nowPlayingTitle;
@InjectView(R.id.details) TextView nowPlayingDetails;
@ -145,11 +152,6 @@ public class RemoteFragment extends Fragment
@InjectView(R.id.rewind) ImageButton rewindButton;
@InjectView(R.id.fast_forward) ImageButton fastForwardButton;
private Animation buttonInAnim;
private Animation buttonOutAnim;
// Touch listener that provides touch feedback
private View.OnTouchListener feedbackTouchListener;
// EventServer connection
private EventServerConnection eventServerConnection = null;
@ -162,27 +164,7 @@ public class RemoteFragment extends Fragment
hostManager = HostManager.getInstance(getActivity());
hostConnectionObserver = hostManager.getHostConnectionObserver();
buttonInAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.button_in);
buttonOutAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.button_out);
createEventServerConnection();
feedbackTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
buttonInAnim.setFillAfter(true);
v.startAnimation(buttonInAnim);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
v.startAnimation(buttonOutAnim);
break;
}
return false;
}
};
}
@Override
@ -190,43 +172,9 @@ public class RemoteFragment extends Fragment
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_remote, container, false);
ButterKnife.inject(this, root);
if (hostManager.getHostInfo().getUseEventServer() &&
(eventServerConnection != null)) {
// Setup d-pad to use EventServer
setupEventServerButton(leftButton, ButtonCodes.REMOTE_LEFT);
setupEventServerButton(rightButton, ButtonCodes.REMOTE_RIGHT);
setupEventServerButton(upButton, ButtonCodes.REMOTE_UP);
setupEventServerButton(downButton, ButtonCodes.REMOTE_DOWN);
controlPad.setOnPadButtonsListener(this);
setupEventServerButton(selectButton, ButtonCodes.REMOTE_SELECT);
} else {
// Otherwise, use json-rpc
setupRepeatButton(leftButton, new Input.Left());
setupRepeatButton(rightButton, new Input.Right());
setupRepeatButton(upButton, new Input.Up());
setupRepeatButton(downButton, new Input.Down());
setupDefaultButton(selectButton, new Input.Select(), null);
}
// Other buttons
setupDefaultButton(backButton, new Input.Back(), null);
setupDefaultButton(osdButton, new Input.ExecuteAction(Input.ExecuteAction.OSD), null);
setupDefaultButton(contextButton, new Input.ExecuteAction(Input.ExecuteAction.CONTEXTMENU), null);
// Info button, v17 uses a different window to display codec info so check version number
HostInfo hostInfo = hostManager.getHostInfo();
if (hostInfo.getKodiVersionMajor() < 17) {
setupDefaultButton(infoButton,
new Input.ExecuteAction(Input.ExecuteAction.INFO),
new Input.ExecuteAction(Input.ExecuteAction.CODECINFO));
} else {
setupDefaultButton(infoButton,
new Input.ExecuteAction(Input.ExecuteAction.INFO),
new Input.ExecuteAction(Input.ExecuteAction.PLAYERPROCESSINFO));
}
adjustRemoteButtons();
TypedArray styledAttributes = getActivity().getTheme().obtainStyledAttributes(new int[] {
R.attr.iconFastForward,
@ -253,53 +201,9 @@ public class RemoteFragment extends Fragment
buttons[i].setVisibility(shownItems.contains(String.valueOf(i)) ? View.VISIBLE : View.GONE);
}
// // Pad main content view to account for bottom system bar
// UIUtils.setPaddingForSystemBars(getActivity(), root, false, false, true);
// No clipping
// root.setClipToPadding(false);
return root;
}
@TargetApi(21)
private void adjustRemoteButtons() {
Resources.Theme theme = getActivity().getTheme();
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
R.attr.remoteButtonColorFilter,
R.attr.contentBackgroundColor});
// R.attr.remoteBackgroundColorFilter});
Resources resources = getResources();
int remoteButtonsColor = styledAttributes.getColor(styledAttributes.getIndex(0), resources.getColor(R.color.white)),
remoteBackgroundColor = styledAttributes.getColor(styledAttributes.getIndex(1), resources.getColor(R.color.dark_content_background_dim_70pct));
styledAttributes.recycle();
leftButton.setColorFilter(remoteButtonsColor);
rightButton.setColorFilter(remoteButtonsColor);
upButton.setColorFilter(remoteButtonsColor);
downButton.setColorFilter(remoteButtonsColor);
selectButton.setColorFilter(remoteButtonsColor);
backButton.setColorFilter(remoteButtonsColor);
infoButton.setColorFilter(remoteButtonsColor);
osdButton.setColorFilter(remoteButtonsColor);
contextButton.setColorFilter(remoteButtonsColor);
// On ICS the remote background isn't shown as the tinting isn't supported
//int backgroundResourceId = R.drawable.remote_background_square_black_alpha;
int backgroundResourceId = R.drawable.remote_background_square_black;
if (Utils.isLollipopOrLater()) {
remotePanel.setBackgroundTintList(ColorStateList.valueOf(remoteBackgroundColor));
remotePanel.setBackgroundResource(backgroundResourceId);
} else if (Utils.isJellybeanOrLater()) {
BitmapDrawable background = new BitmapDrawable(getResources(),
BitmapFactory.decodeResource(getResources(), backgroundResourceId));
background.setColorFilter(new PorterDuffColorFilter(remoteBackgroundColor, PorterDuff.Mode.SRC_IN));
remotePanel.setBackground(background);
}
}
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -338,91 +242,6 @@ public class RemoteFragment extends Fragment
});
}
private void setupRepeatButton(View button, final ApiMethod<String> action) {
button.setOnTouchListener(new RepeatListener(UIUtils.initialButtonRepeatInterval, UIUtils.buttonRepeatInterval,
new View.OnClickListener() {
@Override
public void onClick(View v) {
action.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}, buttonInAnim, buttonOutAnim, getActivity().getApplicationContext()));
}
private void setupDefaultButton(View button,
final ApiMethod<String> clickAction,
final ApiMethod<String> longClickAction) {
// Set animation
button.setOnTouchListener(feedbackTouchListener);
if (clickAction != null) {
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UIUtils.handleVibration(getActivity());
clickAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
});
}
if (longClickAction != null) {
button.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
UIUtils.handleVibration(getActivity());
longClickAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
return true;
}
});
}
}
private void setupEventServerButton(View button, final String action) {
final Packet packet =
new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, false, true, true, (short)0, (byte)0);
button.setOnTouchListener(new RepeatListener(UIUtils.initialButtonRepeatInterval, UIUtils.buttonRepeatInterval,
new View.OnClickListener() {
@Override
public void onClick(View v) {
if (eventServerConnection != null)
eventServerConnection.sendPacket(packet);
}
}, buttonInAnim, buttonOutAnim, getActivity().getApplicationContext()));
}
// private void setupEventServerButton(View button, final String action) {
// short amount = 0;
// byte axis = 0;
// final Packet packetDown =
// new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, true, true, false, amount, axis);
// final Packet packetUp =
// new PacketBUTTON(ButtonCodes.MAP_REMOTE, action, false, false, false, amount, axis);
//
// // Set animation and packet
// button.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// buttonInAnim.setFillAfter(true);
// v.startAnimation(buttonInAnim);
// eventServerConnection.sendPacket(packetDown);
// break;
// case MotionEvent.ACTION_UP:
// case MotionEvent.ACTION_CANCEL:
// v.startAnimation(buttonOutAnim);
// eventServerConnection.sendPacket(packetUp);
// break;
// }
// return false;
// }
// });
// button.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// // Nothing to do
// }
// });
// }
/**
* Default callback for methods that don't return anything
*/
@ -731,11 +550,92 @@ public class RemoteFragment extends Fragment
}
if (showRemote) {
remotePanel.setVisibility(View.VISIBLE);
controlPad.setVisibility(View.VISIBLE);
buttonBarPanel.setVisibility(View.VISIBLE);
} else {
remotePanel.setVisibility(View.GONE);
controlPad.setVisibility(View.GONE);
buttonBarPanel.setVisibility(View.GONE);
}
}
@Override
public void leftButtonClicked() {
if (eventServerConnection != null) {
eventServerConnection.sendPacket(leftButtonPacket);
} else {
leftButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}
@Override
public void rightButtonClicked() {
if (eventServerConnection != null) {
eventServerConnection.sendPacket(rightButtonPacket);
} else {
rightButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}
@Override
public void upButtonClicked() {
if (eventServerConnection != null) {
eventServerConnection.sendPacket(upButtonPacket);
} else {
upButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}
@Override
public void downButtonClicked() {
if (eventServerConnection != null) {
eventServerConnection.sendPacket(downButtonPacket);
} else {
downButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}
@Override
public void selectButtonClicked() {
if (eventServerConnection != null) {
eventServerConnection.sendPacket(selectButtonPack);
} else {
selectButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}
@Override
public void backButtonClicked() {
backButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
@Override
public void infoButtonClicked() {
infoButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
@Override
public boolean infoButtonLongClicked() {
ApiMethod<String> action;
HostInfo hostInfo = hostManager.getHostInfo();
// Info button, v17 uses a different window to display codec info so check version number
if (hostInfo.getKodiVersionMajor() < 17) {
action = new Input.ExecuteAction(Input.ExecuteAction.CODECINFO);
} else {
action = new Input.ExecuteAction(Input.ExecuteAction.PLAYERPROCESSINFO);
}
action.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
return true;
}
@Override
public void contextButtonClicked() {
contextButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
@Override
public void osdButtonClicked() {
osdButtonAction.execute(hostManager.getConnection(), defaultActionCallback, callbackHandler);
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2017 Martijn Brekhof. All rights reserved.
*
* 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 org.xbmc.kore.ui.viewgroups;
import android.content.Context;
import android.support.v7.widget.GridLayout;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import org.xbmc.kore.utils.LogUtils;
/**
* The square grid layout creates a square layout that will fit inside
* the boundaries provided by the parent layout.
*/
public class SquareGridLayout extends GridLayout {
public SquareGridLayout(Context context) {
super(context);
fixForRelativeLayout();
}
public SquareGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
fixForRelativeLayout();
}
public SquareGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
fixForRelativeLayout();
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
int width = MeasureSpec.getSize(widthSpec);
int height = MeasureSpec.getSize(heightSpec);
int size = Math.min(width, height);
super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
}
/**
* When used in a relative layout we need to set the layout parameters to
* the correct size manually. Otherwise the grid layout will be stretched.
*/
private void fixForRelativeLayout() {
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewGroup.LayoutParams pParams = getLayoutParams();
if (pParams instanceof RelativeLayout.LayoutParams) {
int size = Math.min(getWidth(), getHeight());
pParams.width = size;
pParams.height = size;
setLayoutParams(pParams);
}
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
}

View File

@ -0,0 +1,240 @@
/*
* Copyright 2017 Martijn Brekhof. All rights reserved.
*
* 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 org.xbmc.kore.ui.widgets;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.BitmapFactory;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import org.xbmc.kore.R;
import org.xbmc.kore.ui.viewgroups.SquareGridLayout;
import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.RepeatListener;
import org.xbmc.kore.utils.Utils;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class ControlPad extends SquareGridLayout
implements View.OnClickListener, View.OnLongClickListener {
private static final String TAG = LogUtils.makeLogTag(ControlPad.class);
private static final int initialButtonRepeatInterval = 400; // ms
private static final int buttonRepeatInterval = 80; // ms
public interface OnPadButtonsListener {
void leftButtonClicked();
void rightButtonClicked();
void upButtonClicked();
void downButtonClicked();
void selectButtonClicked();
void backButtonClicked();
void infoButtonClicked();
boolean infoButtonLongClicked();
void contextButtonClicked();
void osdButtonClicked();
}
private OnPadButtonsListener onPadButtonsListener;
@InjectView(R.id.select) ImageView selectButton;
@InjectView(R.id.left) ImageView leftButton;
@InjectView(R.id.right) ImageView rightButton;
@InjectView(R.id.up) ImageView upButton;
@InjectView(R.id.down) ImageView downButton;
@InjectView(R.id.back) ImageView backButton;
@InjectView(R.id.info) ImageView infoButton;
@InjectView(R.id.context) ImageView contextButton;
@InjectView(R.id.osd) ImageView osdButton;
public ControlPad(Context context) {
super(context);
initializeView(context);
}
public ControlPad(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView(context);
}
public ControlPad(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeView(context);
}
@Override
public void setOnClickListener(@Nullable View.OnClickListener l) {
throw new Error("Use setOnPadButtonsListener(listener)");
}
@Override
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
throw new Error("Use setOnPadButtonsListener(listener)");
}
public void setOnPadButtonsListener(OnPadButtonsListener onPadButtonsListener) {
this.onPadButtonsListener = onPadButtonsListener;
}
private void initializeView(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.remote_control_pad, this);
ButterKnife.inject(this, this);
applyTheme();
setupListeners(context);
}
@Override
public void onClick(View v) {
if (onPadButtonsListener == null)
return;
switch (v.getId()) {
case R.id.select:
onPadButtonsListener.selectButtonClicked();
break;
case R.id.left:
onPadButtonsListener.leftButtonClicked();
break;
case R.id.right:
onPadButtonsListener.rightButtonClicked();
break;
case R.id.up:
onPadButtonsListener.upButtonClicked();
break;
case R.id.down:
onPadButtonsListener.downButtonClicked();
break;
case R.id.back:
onPadButtonsListener.backButtonClicked();
break;
case R.id.info:
onPadButtonsListener.infoButtonClicked();
break;
case R.id.context:
onPadButtonsListener.contextButtonClicked();
break;
case R.id.osd:
onPadButtonsListener.osdButtonClicked();
break;
default:
LogUtils.LOGD(TAG, "Unknown button "+v.getId()+" clicked");
}
}
@Override
public boolean onLongClick(View v) {
if ((onPadButtonsListener != null) && (v.getId() == R.id.info)) {
return onPadButtonsListener.infoButtonLongClicked();
}
return false;
}
@TargetApi(21)
private void applyTheme() {
Resources.Theme theme = getContext().getTheme();
TypedArray styledAttributes = theme.obtainStyledAttributes(new int[] {
R.attr.remoteButtonColorFilter,
R.attr.contentBackgroundColor});
Resources resources = getResources();
int remoteButtonsColor = styledAttributes.getColor(styledAttributes.getIndex(0), resources.getColor(R.color.white)),
remoteBackgroundColor = styledAttributes.getColor(styledAttributes.getIndex(1), resources.getColor(R.color.dark_content_background_dim_70pct));
styledAttributes.recycle();
leftButton.setColorFilter(remoteButtonsColor);
rightButton.setColorFilter(remoteButtonsColor);
upButton.setColorFilter(remoteButtonsColor);
downButton.setColorFilter(remoteButtonsColor);
selectButton.setColorFilter(remoteButtonsColor);
backButton.setColorFilter(remoteButtonsColor);
infoButton.setColorFilter(remoteButtonsColor);
osdButton.setColorFilter(remoteButtonsColor);
contextButton.setColorFilter(remoteButtonsColor);
// On ICS the remote background isn't shown as the tinting isn't supported
//int backgroundResourceId = R.drawable.remote_background_square_black_alpha;
int backgroundResourceId = R.drawable.remote_background_square_black;
if (Utils.isLollipopOrLater()) {
setBackgroundTintList(ColorStateList.valueOf(remoteBackgroundColor));
setBackgroundResource(backgroundResourceId);
} else if (Utils.isJellybeanOrLater()) {
BitmapDrawable background = new BitmapDrawable(getResources(),
BitmapFactory.decodeResource(getResources(), backgroundResourceId));
background.setColorFilter(new PorterDuffColorFilter(remoteBackgroundColor, PorterDuff.Mode.SRC_IN));
setBackground(background);
}
}
private void setupListeners(Context context) {
final Animation buttonInAnim = AnimationUtils.loadAnimation(context, R.anim.button_in);
final Animation buttonOutAnim = AnimationUtils.loadAnimation(context, R.anim.button_out);
RepeatListener repeatListener = new RepeatListener(initialButtonRepeatInterval,
buttonRepeatInterval, this,
buttonInAnim, buttonOutAnim, getContext());
OnTouchListener feedbackTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
buttonInAnim.setFillAfter(true);
v.startAnimation(buttonInAnim);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
v.startAnimation(buttonOutAnim);
break;
}
return false;
}
};
leftButton.setOnTouchListener(repeatListener);
rightButton.setOnTouchListener(repeatListener);
upButton.setOnTouchListener(repeatListener);
downButton.setOnTouchListener(repeatListener);
setupButton(selectButton, feedbackTouchListener);
setupButton(backButton, feedbackTouchListener);
setupButton(infoButton, feedbackTouchListener);
setupButton(contextButton, feedbackTouchListener);
setupButton(osdButton, feedbackTouchListener);
}
private void setupButton(View button, OnTouchListener feedbackTouchListener) {
button.setOnTouchListener(feedbackTouchListener);
button.setOnClickListener(this);
button.setOnLongClickListener(this);
}
}

View File

@ -15,6 +15,7 @@
*/
package org.xbmc.kore.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@ -26,6 +27,7 @@ import android.os.Build;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.widget.Toast;
import org.xbmc.kore.R;
@ -241,4 +243,18 @@ public class Utils {
}
}, callbackHandler);
}
/**
* Returns the smallest width in density independent pixel size.
* Useful to determine in which sw<SIZE>dp bucket the device is placed.
* @param activity
* @return the smallest width in density independent pixel size
*/
public static int getSmallestWidthDP(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
float widthDp = metrics.widthPixels / metrics.density;
float heightDp = metrics.heightPixels / metrics.density;
return (int) Math.min(widthDp, heightDp);
}
}

View File

@ -15,218 +15,19 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<!-- For when nothing is playing or something not recognized is playing -->
<RelativeLayout
android:id="@+id/info_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingTop="@dimen/remote_page_indicator_height"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
tools:ignore="InconsistentLayout"
tools:visibility="gone">
<!--android:background="?attr/cardBackground">-->
<TextView
android:id="@+id/info_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Title"
tools:ignore="InconsistentLayout"/>
<TextView
android:id="@+id/info_message"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Details"
android:layout_below="@id/info_title"
tools:ignore="InconsistentLayout"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/media_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin">
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:contentDescription="@string/poster"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
style="@style/TextAppearance.Media.Remote.Title"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignLeft="@id/title"
android:layout_alignStart="@id/title"
style="@style/TextAppearance.Media.Remote.Details"
android:background="?attr/contentBackgroundColor"/>
<LinearLayout
android:id="@+id/media_button_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_below="@id/details"
android:layout_alignLeft="@id/details"
android:layout_alignStart="@id/details"
android:layout_alignBottom="@+id/art"
android:orientation="horizontal"
style="@style/ButtonBar"
android:background="?attr/contentBackgroundColor">
<ImageButton
android:id="@+id/rewind"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconRewind"
android:contentDescription="@string/rewind"/>
<ImageButton
android:id="@+id/play"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPlay"
android:contentDescription="@string/play"/>
<ImageButton
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconStop"
android:contentDescription="@string/stop"/>
<ImageButton
android:id="@+id/fast_forward"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFastForward"
android:contentDescription="@string/fast_forward"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/remote"
android:layout_width="@dimen/remote_size"
android:layout_height="@dimen/remote_size"
android:layout_marginRight="@dimen/remote_content_hmargin"
android:layout_marginEnd="@dimen/remote_content_hmargin"
android:layout_gravity="center">
<ImageView
android:id="@+id/context"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:src="?attr/iconContext"
android:contentDescription="@string/codec_info"/>
<ImageView
android:id="@+id/up"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/context"
android:layout_toEndOf="@id/context"
android:layout_alignTop="@id/context"
android:src="?attr/iconUp"
android:contentDescription="@string/up"/>
<ImageView
android:id="@+id/info"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/up"
android:layout_toEndOf="@id/up"
android:layout_alignTop="@id/context"
android:src="?attr/iconInfo"
android:contentDescription="@string/info"/>
<ImageView
android:id="@+id/left"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_below="@id/context"
android:src="?attr/iconLeft"
android:contentDescription="@string/left"/>
<ImageView
android:id="@+id/select"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/left"
android:layout_toEndOf="@id/left"
android:layout_alignTop="@id/left"
android:src="?attr/iconSelect"
android:contentDescription="@string/select"/>
<ImageView
android:id="@+id/right"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/select"
android:layout_toEndOf="@id/select"
android:layout_alignTop="@id/left"
android:src="?attr/iconRight"
android:contentDescription="@string/right"/>
<ImageView
android:id="@+id/back"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_below="@id/left"
android:src="?attr/iconBack"
android:contentDescription="@string/back"/>
<ImageView
android:id="@+id/down"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/back"
android:layout_toEndOf="@id/back"
android:layout_alignTop="@id/back"
android:src="?attr/iconDown"
android:contentDescription="@string/down"/>
<ImageView
android:id="@+id/osd"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/down"
android:layout_toEndOf="@id/down"
android:layout_alignTop="@id/back"
android:src="?attr/iconMenu"
android:contentDescription="@string/osd"/>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Right button bar -->
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="@dimen/buttonbar_height"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:orientation="vertical"
style="@style/ButtonBar.Bottom">
<ImageButton
@ -329,4 +130,131 @@
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/system"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@+id/button_bar"
android:layout_toStartOf="@+id/button_bar">
<!-- For when nothing is playing or something not recognized is playing -->
<RelativeLayout
android:id="@+id/info_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingTop="@dimen/remote_page_indicator_height"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
tools:ignore="InconsistentLayout"
tools:visibility="gone">
<!--android:background="?attr/cardBackground">-->
<TextView
android:id="@+id/info_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Title"
tools:ignore="InconsistentLayout"/>
<TextView
android:id="@+id/info_message"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Details"
android:layout_below="@id/info_title"
tools:ignore="InconsistentLayout"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/media_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/remote_content_hmargin">
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:contentDescription="@string/poster"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
style="@style/TextAppearance.Media.Remote.Title"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignLeft="@id/title"
android:layout_alignStart="@id/title"
style="@style/TextAppearance.Media.Remote.Details"
android:background="?attr/contentBackgroundColor"/>
<LinearLayout
android:id="@+id/media_button_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_below="@id/details"
android:layout_alignLeft="@id/details"
android:layout_alignStart="@id/details"
android:layout_alignBottom="@+id/art"
android:orientation="horizontal"
style="@style/ButtonBar"
android:background="?attr/contentBackgroundColor">
<ImageButton
android:id="@+id/rewind"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconRewind"
android:contentDescription="@string/rewind"/>
<ImageButton
android:id="@+id/play"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPlay"
android:contentDescription="@string/play"/>
<ImageButton
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconStop"
android:contentDescription="@string/stop"/>
<ImageButton
android:id="@+id/fast_forward"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFastForward"
android:contentDescription="@string/fast_forward"/>
</LinearLayout>
</RelativeLayout>
<org.xbmc.kore.ui.widgets.ControlPad
android:id="@+id/remote"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_gravity="end|center_vertical"
app:columnCount="3"/>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015 Synced Synapse. All rights reserved.
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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:baselineAligned="false">
<!-- For when nothing is playing or something not recognized is playing -->
<RelativeLayout
android:id="@+id/info_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingTop="@dimen/remote_page_indicator_height"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
tools:ignore="InconsistentLayout"
tools:visibility="gone">
<!--android:background="?attr/cardBackground">-->
<TextView
android:id="@+id/info_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Title"
tools:ignore="InconsistentLayout"/>
<TextView
android:id="@+id/info_message"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
style="@style/TextAppearance.Info.Details"
android:layout_below="@id/info_title"
tools:ignore="InconsistentLayout"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/media_panel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin">
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:contentDescription="@string/poster"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
style="@style/TextAppearance.Media.Remote.Title"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignLeft="@id/title"
android:layout_alignStart="@id/title"
style="@style/TextAppearance.Media.Remote.Details"
android:background="?attr/contentBackgroundColor"/>
<LinearLayout
android:id="@+id/media_button_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_below="@id/details"
android:layout_alignLeft="@id/details"
android:layout_alignStart="@id/details"
android:layout_alignBottom="@+id/art"
android:orientation="horizontal"
style="@style/ButtonBar"
android:background="?attr/contentBackgroundColor">
<ImageButton
android:id="@+id/rewind"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconRewind"
android:contentDescription="@string/rewind"/>
<ImageButton
android:id="@+id/play"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPlay"
android:contentDescription="@string/play"/>
<ImageButton
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconStop"
android:contentDescription="@string/stop"/>
<ImageButton
android:id="@+id/fast_forward"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFastForward"
android:contentDescription="@string/fast_forward"/>
</LinearLayout>
</RelativeLayout>
<org.xbmc.kore.ui.widgets.ControlPad
android:id="@+id/remote"
android:layout_width="@dimen/remote_size"
android:layout_height="@dimen/remote_size"
android:layout_marginRight="@dimen/remote_content_hmargin"
android:layout_marginEnd="@dimen/remote_content_hmargin"
android:layout_gravity="center"
app:columnCount="3"/>
<!-- Right button bar -->
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="@dimen/buttonbar_height"
android:layout_height="match_parent"
android:orientation="vertical"
style="@style/ButtonBar.Bottom">
<ImageButton
android:id="@+id/home"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconHome"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/home"/>
<ImageButton
android:id="@+id/movies"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconMovies"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/movies"/>
<ImageButton
android:id="@+id/tv_shows"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconTvShows"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/tv_shows"/>
<ImageButton
android:id="@+id/music"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconMusic"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/music"/>
<ImageButton
android:id="@+id/pvr"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPVR"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/pvr"/>
<ImageButton
android:id="@+id/pictures"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPicture"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/pictures"/>
<ImageButton
android:id="@+id/videos"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconVideo"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/videos"/>
<!-- <ImageButton
android:id="@+id/favourites"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFavourites"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/favourites"/> -->
<ImageButton
android:id="@+id/addons"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconAddons"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/addons"/>
<ImageButton
android:id="@+id/weather"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconWeather"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/weather"/>
<ImageButton
android:id="@+id/system"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconSettings"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/system"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,244 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015 Synced Synapse. All rights reserved.
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.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include layout="@layout/remote_info_panel"/>
<RelativeLayout
android:id="@+id/media_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
android:paddingTop="@dimen/remote_page_indicator_height">
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="@string/poster"
android:scaleType="centerCrop"/>
<LinearLayout
android:id="@+id/media_button_bar"
style="@style/ButtonBar"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_alignBottom="@id/art"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"
android:orientation="horizontal">
<ImageButton
android:id="@+id/rewind"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/rewind"
android:src="?attr/iconRewind"/>
<ImageButton
android:id="@+id/play"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/play"
android:src="?attr/iconPlay"/>
<ImageButton
android:id="@+id/stop"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/stop"
android:src="?attr/iconStop"/>
<ImageButton
android:id="@+id/fast_forward"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/fast_forward"
android:src="?attr/iconFastForward"/>
</LinearLayout>
<TextView
android:id="@+id/title"
style="@style/TextAppearance.Media.Remote.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/art"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
style="@style/TextAppearance.Media.Remote.Details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/media_button_bar"
android:layout_below="@id/title"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"/>
</RelativeLayout>
<!-- Bottom button bar -->
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/buttonbar_height"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
style="@style/ButtonBar.Bottom">
<ImageButton
android:id="@+id/home"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconHome"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/home"/>
<ImageButton
android:id="@+id/movies"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconMovies"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/movies"/>
<ImageButton
android:id="@+id/tv_shows"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconTvShows"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/tv_shows"/>
<ImageButton
android:id="@+id/music"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconMusic"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/music"/>
<ImageButton
android:id="@+id/pvr"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPVR"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/pvr"/>
<ImageButton
android:id="@+id/pictures"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPicture"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/pictures"/>
<ImageButton
android:id="@+id/videos"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconVideo"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/videos"/>
<!-- <ImageButton
android:id="@+id/favourites"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFavourites"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/favourites"/> -->
<ImageButton
android:id="@+id/addons"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconAddons"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/addons"/>
<ImageButton
android:id="@+id/weather"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconWeather"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/weather"/>
<ImageButton
android:id="@+id/system"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconSettings"
android:tint="?attr/defaultButtonColorFilter"
android:contentDescription="@string/system"/>
</LinearLayout>
<!--
Using the ControlPad with fixed sizes in a RelativeLayout
results in the ControlPad being stretched vertically.
Probably due to a bug in the GridLayout from the appcompat
library. Wrapping it in a FrameLayout fixes this.
-->
<FrameLayout
android:layout_width="@dimen/remote_size"
android:layout_height="@dimen/remote_size"
android:layout_above="@id/button_bar"
android:layout_below="@id/top_panel"
android:layout_centerHorizontal="true"
android:layout_marginBottom="@dimen/default_padding">
<org.xbmc.kore.ui.widgets.ControlPad
android:id="@+id/remote"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
app:columnCount="3"/>
</FrameLayout>
</RelativeLayout>

View File

@ -18,93 +18,105 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<include layout="@layout/remote_info_panel"/>
<RelativeLayout
android:id="@+id/media_panel"
<FrameLayout
android:id="@+id/top_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="@dimen/remote_top_panel_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
android:paddingTop="@dimen/remote_page_indicator_height">
android:layout_alignParentLeft="true">
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:scaleType="centerCrop"
android:contentDescription="@string/poster"/>
<include layout="@layout/remote_info_panel"/>
<LinearLayout
android:id="@+id/media_button_bar"
<RelativeLayout
android:id="@+id/media_panel"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_alignBottom="@id/art"
android:orientation="horizontal"
style="@style/ButtonBar"
android:background="?attr/contentBackgroundColor">
<ImageButton
android:id="@+id/rewind"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconRewind"
android:contentDescription="@string/rewind"/>
<ImageButton
android:id="@+id/play"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconPlay"
android:contentDescription="@string/play"/>
<ImageButton
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconStop"
android:contentDescription="@string/stop"/>
<ImageButton
android:id="@+id/fast_forward"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
style="@style/Widget.Button.Borderless"
android:src="?attr/iconFastForward"
android:contentDescription="@string/fast_forward"/>
</LinearLayout>
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/remote_content_hmargin"
android:layout_marginRight="@dimen/remote_content_hmargin"
android:paddingTop="@dimen/remote_page_indicator_height">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_alignTop="@id/art"
style="@style/TextAppearance.Media.Remote.Title"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/art"
android:layout_toEndOf="@id/art"
android:layout_below="@id/title"
android:layout_above="@id/media_button_bar"
style="@style/TextAppearance.Media.Remote.Details"
android:background="?attr/contentBackgroundColor"/>
</RelativeLayout>
<ImageView
android:id="@+id/art"
android:layout_width="@dimen/remote_poster_width"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:contentDescription="@string/poster"
android:scaleType="centerCrop"/>
<LinearLayout
android:id="@+id/media_button_bar"
style="@style/ButtonBar"
android:layout_width="match_parent"
android:layout_height="@dimen/default_icon_size"
android:layout_alignBottom="@id/art"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"
android:orientation="horizontal">
<ImageButton
android:id="@+id/rewind"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/rewind"
android:src="?attr/iconRewind"/>
<ImageButton
android:id="@+id/play"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/play"
android:src="?attr/iconPlay"/>
<ImageButton
android:id="@+id/stop"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/stop"
android:src="?attr/iconStop"/>
<ImageButton
android:id="@+id/fast_forward"
style="@style/Widget.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/fast_forward"
android:src="?attr/iconFastForward"/>
</LinearLayout>
<TextView
android:id="@+id/title"
style="@style/TextAppearance.Media.Remote.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/art"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"/>
<TextView
android:id="@+id/details"
style="@style/TextAppearance.Media.Remote.Details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/media_button_bar"
android:layout_below="@id/title"
android:layout_toEndOf="@id/art"
android:layout_toRightOf="@id/art"
android:background="?attr/contentBackgroundColor"/>
</RelativeLayout>
</FrameLayout>
<!-- Bottom button bar -->
<LinearLayout
@ -215,91 +227,13 @@
android:contentDescription="@string/system"/>
</LinearLayout>
<RelativeLayout
<org.xbmc.kore.ui.widgets.ControlPad
android:id="@+id/remote"
android:layout_width="@dimen/remote_size"
android:layout_height="@dimen/remote_size"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/button_bar"
android:layout_marginBottom="@dimen/default_padding"
android:layout_centerHorizontal="true">
android:layout_below="@id/top_panel"
android:layout_centerHorizontal="true"
app:columnCount="3"/>
<ImageView
android:id="@+id/context"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:src="?attr/iconContext"
android:contentDescription="@string/codec_info"/>
<ImageView
android:id="@+id/up"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/context"
android:layout_toEndOf="@id/context"
android:layout_alignTop="@id/context"
android:src="?attr/iconUp"
android:contentDescription="@string/up"/>
<ImageView
android:id="@+id/info"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/up"
android:layout_toEndOf="@id/up"
android:layout_alignTop="@id/context"
android:src="?attr/iconInfo"
android:contentDescription="@string/info"/>
<ImageView
android:id="@+id/left"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_below="@id/context"
android:src="?attr/iconLeft"
android:contentDescription="@string/left"/>
<ImageView
android:id="@+id/select"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/left"
android:layout_toEndOf="@id/left"
android:layout_alignTop="@id/left"
android:src="?attr/iconSelect"
android:contentDescription="@string/select"/>
<ImageView
android:id="@+id/right"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/select"
android:layout_toEndOf="@id/select"
android:layout_alignTop="@id/left"
android:src="?attr/iconRight"
android:contentDescription="@string/right"/>
<ImageView
android:id="@+id/back"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_below="@id/left"
android:src="?attr/iconBack"
android:contentDescription="@string/back"/>
<ImageView
android:id="@+id/down"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/back"
android:layout_toEndOf="@id/back"
android:layout_alignTop="@id/back"
android:src="?attr/iconDown"
android:contentDescription="@string/down"/>
<ImageView
android:id="@+id/osd"
android:layout_width="@dimen/remote_icon_size"
android:layout_height="@dimen/remote_icon_size"
android:layout_toRightOf="@id/down"
android:layout_toEndOf="@id/down"
android:layout_alignTop="@id/back"
android:src="?attr/iconMenu"
android:contentDescription="@string/osd"/>
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Martijn Brekhof. All rights reserved.
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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/context"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconContext"
android:contentDescription="@string/codec_info"/>
<ImageView
android:id="@+id/up"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconUp"
android:contentDescription="@string/up"/>
<ImageView
android:id="@+id/info"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconInfo"
android:contentDescription="@string/info"/>
<ImageView
android:id="@+id/left"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconLeft"
android:contentDescription="@string/left"/>
<ImageView
android:id="@+id/select"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconSelect"
android:contentDescription="@string/select"/>
<ImageView
android:id="@+id/right"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconRight"
android:contentDescription="@string/right"/>
<ImageView
android:id="@+id/back"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconBack"
android:contentDescription="@string/back"/>
<ImageView
android:id="@+id/down"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconDown"
android:contentDescription="@string/down"/>
<ImageView
android:id="@+id/osd"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
app:layout_gravity="fill"
android:src="?attr/iconMenu"
android:contentDescription="@string/osd"/>
</merge>

View File

@ -20,7 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/info_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="@dimen/remote_poster_height"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:paddingTop="@dimen/remote_page_indicator_height"

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="remote_icon_size">58dp</dimen>
<dimen name="remote_size">174dp</dimen>
</resources>

View File

@ -60,6 +60,7 @@
<dimen name="remote_poster_width">98dp</dimen>
<dimen name="remote_poster_height">140dp</dimen>
<dimen name="remote_top_panel_height">164dp</dimen>
<dimen name="now_playing_poster_width">112dp</dimen>
<dimen name="now_playing_poster_height">160dp</dimen>